首页 > 解决方案 > 在没有 FileStreams 的 WAL 模式下备份 sqlite db // 通过导出/备份 sql 命令

问题描述

我在这里搜索了很多答案,但都使用FileInputStreamFileOutputStream备份数据库。

在您使用具有(预写日志记录)、异步模式等的PRAGMA语句时,文件复制会失败。journal_mode=WAL

如何备份/导出/快照在 android 上以 WAL 模式运行的 sqlite 数据库?

文件副本不可能是正确的方法。sqlite 中必须有一些可用的备份/导出命令(嗯,它可以通过 sqlite 命令 shell 获得)。

到目前为止,我还没有找到解决方案。非常感谢任何帮助。

标签: androidsqlite

解决方案


当您将 PRAGMA 语句与 journal_mode=WAL(预写日志记录)、异步模式等一起使用时,文件复制会失败。

简而言之,您需要备份并恢复所有三个文件,或者您需要确保数据库已完全检查点,备份数据库文件并在恢复时删除-wal-shm文件。

这是一个更全面的答案

这是一个在 WAL 模式下检查数据库的方法示例(这用于日志模式可以是 Android 默认值):-

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();
}
  • 请注意,上面的数据库名称是通过常量 DBConstants.DATABSENAME 获得(解析)的,这将是一个简单的签名更改以允许传递数据库名称。

推荐阅读