Как удалить базу метаданных через комнату в Android? - PullRequest
1 голос
/ 11 мая 2019

У меня есть таблица в базе данных комнаты с полем, установленным как index, и это autoincrement.Sqlite сохранит некоторые метаданные в своей основной таблице, чтобы сохранить счетчик последнего автоматически сгенерированного значения.

На основе логики моего приложения я очищу базу данных и сохраню структуру;Предположим, я вставил 3 элемента в базу данных, и упомянутое действие происходит, поэтому я очищаю элементы, но когда я вставляю новый элемент, его автоматически сгенерированное поле будет равно 4, что приведет к переполнению и падению приложения в долгосрочной перспективе.Я обошел его, убрав autoincrement и установив поле вручную!

Теперь мой вопрос: как я могу сбросить значение автоинкрементного поля, которое будет установлено в 1 после каждой очистки базы данных (я предпочитаю только место)?

1 Ответ

1 голос
/ 11 мая 2019

Способ работы автоинкремента заключается в том, что при определении нового значения используются 2 значения: -

  • первое эквивалентно использованию max(the_autoincrement_column) (т. Е. Столбец с псевдонимом rowid столбец с кодировкой AUTOINCREMENT) ,
  • секунда получается из таблицы sqlite_sequence из столбца seq строки, в которой находится таблицаимя в столбце имени.

    • Обратите внимание, что значения хранятся не в главной таблице THE, sqlite_master (схема), а в таблице sqlite_sequence.
    • Таблица sqlite_sequence будет существовать только при использовании AUTOINCREMENT.

1 добавляется к большему значению.

Для сброса теоретически вы должны удалить все строки из таблицы и удалить соответствующую строку из таблицы sqlite_sequence .

Однако помещение защищает системные таблицы.Итак, короче говоря, кажется, что нет возможности использовать пространство, чтобы сделать последнее и, следовательно, проблема. Вот ответ, это пример, который делает выше НО , он должен быть запущен за пределами (до) комнаты и поэтому ограничен.

  • Примечание в ответе есть дополнительный код, который используется для начала нумерации с 0 (триггер).

Однако в отношении переполнениятогда это в принципе крайне маловероятно в соответствии с: -

Максимальное количество строк в таблице

Теоретическое максимальное количество строк в таблице равно 2 в степени 64 (18446744073709551616 или около 1,8e + 19).Этот предел недоступен, так как сначала будет достигнут максимальный размер базы данных в 140 терабайт.База данных объемом 140 терабайт может содержать не более 1e + 13 строк, и только в том случае, если индексов нет и каждая строка содержит очень мало данных. Пределы в SQLite

С автоинкрементом это 2 к степени 63 (9,223,372,036,854,775,808) (без автоинкремента вы можете использовать отрицательные значения (Java), так что вы можете использовать64-й бит, следовательно, торектический максимум) как таковое ограничение скорее всего будет связано с емкостью диска, а не с наивысшим достигаемым идентификатором.

Дополнительно

После некоторой игры, следующее сбрасываетПоследовательность, в то время как Room имеет базу данных.

То есть следующая сборка базы данных Room вставляет две строки, сбрасывает последовательность (включая удаление недавно добавленных строк)

  • , открывая базу данных какстандартная база данных SQLite
    • Обратите внимание на использование как OPENREADWRITE, так и ENABLEWRITEAHEADLOGGING
    • (если не последнее, то предупреждающее сообщение о том, что WAL не может быть отключено, так как база данных открыта, так что это простооткрывает его в режиме WAL)
  • удаление существующих строк в таблице и
  • удалениеизвлекая соответствующую строку из sqlite_sequence и, наконец,
  • закрывая эту другую базу данных.

: -

public class MainActivity extends AppCompatActivity {

    public static final String DBNAME = "mydatabase";
    public static final String MYTABLENAME = "mytable";

    MyDatabase mydb,mydb2;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mydb = Room.databaseBuilder(this,MyDatabase.class,DBNAME).allowMainThreadQueries().build();
        MyTableDAO mytabledao = mydb.getMyTableDAO();
        MyTable mt1 = new MyTable();
        mt1.setName("Test001");
        mytabledao.insert(mt1);
        MyTable mt2 = new MyTable();
        mt2.setName("Test002");
        mytabledao.insert(mt2);
        for (MyTable mt: mytabledao.getAllMyTables()) {
            Log.d("MYTABLEROW","ID=" + String.valueOf(mt.getId()) + " Name=" + mt.getName());
        }

        /*
        while (mydb.isOpen()) {
            mydb.close();
        }
        Ouch if used :-
        E/ROOM: Invalidation tracker is initialized twice :/. (ignored)
        E/ROOM: Cannot run invalidation tracker. Is the db closed?
        java.lang.IllegalStateException: Cannot perform this operation because the connection pool has been closed.
        */
        resetSequencedTable(MYTABLENAME);
        //mydb2 = Room.databaseBuilder(this,MyDatabase.class,DBNAME).allowMainThreadQueries().build(); // No Good

        /*
            Works even though :-
            05-12 12:31:40.112 28585-28585/? D/MYTABLEROW: ID=1 Name=Test001
            05-12 12:31:40.112 28585-28585/? D/MYTABLEROW: ID=2 Name=Test002
            05-12 12:31:40.114 28585-28585/? E/SQLiteLog: (5) statement aborts at 2: [PRAGMA journal_mode=PERSIST]
            05-12 12:31:40.115 28585-28585/? W/SQLiteConnection: Could not change the database journal mode of '/data/user/0/soa.myapplication/databases/mydatabase' from 'wal' to 'PERSIST' because the database is locked.  This usually means that there are other open connections to the database which prevents the database from enabling or disabling write-ahead logging mode.  Proceeding without changing the journal mode.
            05-12 12:31:40.126 28585-28585/? D/MYTABLEROW: ID=1 Name=Test003
            05-12 12:31:40.126 28585-28585/? D/MYTABLEROW: ID=2 Name=Test004
         */

        for (MyTable mt: mytabledao.getAllMyTables()) {
            Log.d("MYTABLEROW","ID=" + String.valueOf(mt.getId()) + " Name=" + mt.getName());
        }
        MyTable mt3 = new MyTable();
        mt3.setName("Test003");
        mytabledao.insert(mt3);
        MyTable mt4 = new MyTable();
        mt4.setName("Test004");
        mytabledao.insert(mt4);
        for (MyTable mt: mytabledao.getAllMyTables()) {
            Log.d("MYTABLEROW","ID=" + String.valueOf(mt.getId()) + " Name=" + mt.getName());
        }
    }

    private void resetSequencedTable(String table) {
        Log.d("RESETSEQ","Initiating sequence reset");
        SQLiteDatabase db = SQLiteDatabase.openDatabase(this.getDatabasePath(DBNAME).toString(),null,SQLiteDatabase.OPEN_READWRITE | SQLiteDatabase.ENABLE_WRITE_AHEAD_LOGGING);
        db.delete(table,null,null);
        String whereclause = "name=?";
        String[] whereargs = new String[]{table};
        db.delete("sqlite_sequence",whereclause,whereargs);
        db.close();
        Log.d("RESETSEQ", "Terminating sequence reset");
    }
}

Объект для таблицы: -

@Entity(tableName = MainActivity.MYTABLENAME)
public class MyTable {
    @PrimaryKey(autoGenerate = true)
    private long id;
    private String name;

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
...