将数据库日志模式从DELETE迁移到WAL

时间:2019-06-27 07:56:00

标签: android sqlite android-sqlite

我在我的应用程序中提供了一些导出/导入功能,现在我看到,如果在较新的android版本中导入旧的导出操作,则会出现问题,因为在运行android 9或更高版本的许多手机上,SQLite数据库请勿使用journal_mode WAL,而不要使用旧手机上的DELETE

信息/执照:

  • 我未在应用内(例如,在SQLiteOpenHelper内)设置手动日记模式
  • 并非所有的android 9手机都启用了此功能(我的运行PIE的S9仍使用DELETE模式),因此在手机上还原旧备份效果很好
  • 在未使用DELETE模式的电话上,恢复的备份使我的应用程序崩溃,因为我的应用程序数据库似乎为空-我不在乎。 f当然,照顾一个空数据库并不能解决问题,因为我需要导入的数据...

问题:

上面引出了以下三个问题:

  • 如何确定当前手机默认使用WAL还是DELETE
  • 如何找出给定*.db文件的模式?
  • 如何为给定的*.db文件更改此模式?

我不想要的

我不想完全禁用我的应用程序内的WAL,我更喜欢一些基于迁移的解决方案

1 个答案:

答案 0 :(得分:2)

  

如何确定当前手机默认使用WAL还是DELETE?

如果设备使用Android 9+,则如果正确实现,则应默认为WAL模式。但是,设备提供商可以提供自定义/旧版实现。因此,您需要按照下面显示/回答的步骤进行检查(实际上,使用下面的方法无需检查)。

崩溃的原因可能是您没有备份在WAL模式处于活动状态时存在的其他-wal和-shm文件。

在实际进行备份之前,我使用下面的代码

  • 显然 DBConstants.DBNAME 是数据库名称
  • ,数据库存储在默认位置( data / data / the_package / databases / ))

:-

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();
}

这两种情况下都有效,因为它通过检查点数据库有效地消除了 -wal -shm 文件(清空)。因此,无需复制 -wal -shm 文件,因为没有未完成的事务需要提交。它适用于任何一种模式。

  

如何找出给定* .db文件的模式?

csr = db.rawQuery("PRAGMA journal_mode",null);行是查询日志模式的行,还有SQLiteDatabase方法isWriteAheadLoggingEnabled返回true或false。

关于:-

  

如何为给定的* .db文件更改此模式?

如果使用Android SDK,则可以使用SQLiteDatabase方法enableWriteAheadLoggingdisableWriteAheadLogging,也可以通过journal_mode pragma进行设置,但要注意何时可以使用承担。 Write-Ahead Logging