Перенос режима журнала базы данных с DELETE на WAL

Я предлагаю некоторую функцию экспорта/импорта внутри своего приложения, и теперь я вижу, что это создает проблемы, если старый экспорт импортируется в более новую версию Android, потому что на многих телефонах с Android 9 или выше SQLite базы данных используют journal_modeWAL вместо DELETE который они использовали на старых телефонах.

Информация/наблюдения:

  • Я НЕ устанавливаю ручной режим журнала внутри своего приложения (например, внутри SQLiteOpenHelper)
  • не на всех телефонах Android 9 это включено (мой S9 с PIE все еще использует режим DELETE), поэтому восстановление старых резервных копий на моем телефоне работает отлично.
  • на телефонах, не использующих режим DELETE, восстановленная резервная копия приводит к сбою моего приложения, потому что база данных кажется пустой для моего приложения, что меня не волнует. f конечно, забота о пустой базе данных не решает проблему, так как мне нужны импортированные данные...

Вопросы:

Выше приводит к следующим 3 вопросам:

  • как я могу узнать, использует ли текущий телефон WAL или DELETE по умолчанию?
  • как я могу узнать режим данного *.db файла?
  • как я могу изменить этот режим для данного *.db файла?

Чего я не хочу

Я не хочу полностью отключать WAL внутри своего приложения, я предпочитаю решение на основе миграции.

1
0
441
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

how can I find out if the current phone uses WAL or DELETE by default?

Если устройство использует Android 9+, то при правильной реализации оно должно по умолчанию работать в режиме WAL. Однако поставщики устройств могут предоставлять собственные/устаревшие реализации. Таким образом, вам нужно будет проверить, как показано/отвечено ниже (на самом деле, используя приведенный ниже метод, нет необходимости проверять).

Причина сбоя, вероятно, заключается в том, что вы не создаете резервные копии дополнительных файлов -wal и -shm, которые существуют, когда активен режим WAL.

Я использую приведенный ниже код перед тем, как сделать резервную копию

  • очевидно, DBConstants.DBNAME - это имя базы данных
  • и база данных хранится в расположении по умолчанию (данные/данные/the_package/базы данных/))

:-

private void checkpointIfWALEnabled(Context context) {
    final String TAG = "WALCHKPNT";
    Cursor csr;
    int wal_busy = -99, wal_log = -99, wal_checkpointed = -99;
    SQLiteDatabase db = SQLiteDatabase.openDatabase(context.getDatabasePath(DBConstants.DATABASE_NAME).getPath(),null,SQLiteDatabase.OPEN_READWRITE);
    csr = db.rawQuery("PRAGMA journal_mode",null);
    if (csr.moveToFirst()) {
        String mode = csr.getString(0);
        //Log.d(TAG, "Mode is " + mode);
        if (mode.toLowerCase().equals("wal")) {
            csr = db.rawQuery("PRAGMA wal_checkpoint",null);
            if (csr.moveToFirst()) {
                wal_busy = csr.getInt(0);
                wal_log = csr.getInt(1);
                wal_checkpointed = csr.getInt(2);
            }
            //Log.d(TAG,"Checkpoint pre checkpointing Busy = " + String.valueOf(wal_busy) + " LOG = " + String.valueOf(wal_log) + " CHECKPOINTED = " + String.valueOf(wal_checkpointed) );
            csr = db.rawQuery("PRAGMA wal_checkpoint(TRUNCATE)",null);
            csr.getCount();
            csr = db.rawQuery("PRAGMA wal_checkpoint",null);
            if (csr.moveToFirst()) {
                wal_busy = csr.getInt(0);
                wal_log = csr.getInt(1);
                wal_checkpointed = csr.getInt(2);
            }
            //Log.d(TAG,"Checkpoint post checkpointing Busy = " + String.valueOf(wal_busy) + " LOG = " + String.valueOf(wal_log) + " CHECKPOINTED = " + String.valueOf(wal_checkpointed) );
        }
    }
    csr.close();
    db.close();
}

Это работает в любом случае, так как эффективно удаляет файлы -вал и -шм (очищает их) путем создания контрольных точек в базе данных. Таким образом, нет необходимости копировать файлы -вал и -шм, если нет незавершенных транзакций, которые необходимо зафиксировать. Он работает для любого режима.

how can I find out the mode of a given *.db file?

Строка csr = db.rawQuery("PRAGMA journal_mode",null); — это строка, которая опрашивает режим журнала, также есть метод SQLiteDatabase isWriteAheadLoggingEnabled, который возвращает true или false.

В отношении :-

how can I change this mode for a given *.db file?

Если вы используете Android SDK, вы можете использовать метод SQLiteDatabase включитьWriteAheadLogging или отключитьWriteAheadLogging, или вы можете установить его с помощью Прагма журнал_режим, НО принимая во внимание ограничения относительно того, когда это может быть выполнено. Ведение журнала с опережающей записью

Если я решу отключить режим WAL во всех версиях Android, все, что мне нужно сделать, это следующее: 1) в моей следующей версии приложения я удостоверюсь, что моя база данных еще не открыта, чтобы код не обращался к базе данных 2) я выполняю дольше блок кода, который вы разместили выше, это гарантирует, что все изменения будут записаны в файл базы данных. 3) Я открываю свою базу данных с помощью моего SQLiteOpenHelper, как всегда, и вызываю disableWriteAheadLogging в нем, когда я настраиваю базу данных. Это должно быть сохранено для всех устройств и убедиться, что все устройства используют старый режим журнала, верно?

prom85 01.07.2019 10:42

@ prom85, да, это звучит правильно. Обратите внимание, что приведенный выше код предполагает, что соединение dbHelper было закрыто (в любом случае закрытие должно зафиксировать / контрольная точка).

MikeT 01.07.2019 10:50

после перезапуска приложения оно точно закрывается, так что большое спасибо за очень полезную помощь

prom85 01.07.2019 10:57

Другие вопросы по теме