备份室数据库

问题描述 投票:14回答:4

我正在尝试以编程方式备份​​房间数据库。

为此,我只是复制包含整个数据库的.sqlite文件

但是,在复制之前,由于房间已启用写入日志记录,我们必须关闭数据库,以便-shm文件和-wal文件合并为单个.sqlite文件。 As pointed out here

我在.close()对象上运行RoomDatabase

一切正常,备份,但是,稍后,当我尝试执行INSERT查询时,我收到此错误:

android.database.sqlite.SQLiteException: no such table: room_table_modification_log (code 1)

关闭后如何才能正确地重新打开房间数据库?

PS:.isOpen()对象上的RoomDatabasetrue之前返回INSERT

房间版:1.1.1-rc1

android sqlite android-room sqliteopenhelper android-architecture-components
4个回答
12
投票

关闭后如何才能正确地重新打开房间数据库?

对不起,我对这个问题没有答案。

但是将所有内容移动到原始数据库文件是您要执行的操作,然后您不必关闭数据库。您可以使用wal_checkpoint编译指示强制检查点。

根据数据库查询以下语句。我们在这里使用原始查询,因为Room尚不支持pragma(它将触发UNKNOWN query type错误)。在你的DAO中有这个查询:

@RawQuery
int checkpoint(SupportSQLiteQuery supportSQLiteQuery);

然后在调用checkpoint方法时,使用查询:

myDAO.checkpoint(new SimpleSQLiteQuery("pragma wal_checkpoint(full)"));

This链接可能会阐明wal_checkpoint的作用。


7
投票

为了更具体地回答您的问题,这是我在我的一个应用程序中备份房间数据库的方式。

  1. 检查是否允许读取/写入外部存储。如果您写入App文件目录,则可以忽略此步骤。
  2. 关闭你的RoomDatabase。在我的例子中,AppDatabase指的是包含最初构建房间数据库的逻辑的单例。 AppDatabase.getInstance(this).getDatabase()获取单例的当前实例,以及从RoomDatabase扩展的当前数据库类。这基本上叫RoomDatabase.close()
  3. 根据备份或还原,定义源文件和目标文件。我包括shm和wal文件,即使它们是临时文件。
  4. 使用您选择的方法复制文件。在这种情况下,FileUtils指的是commons-io

The code

if(id == R.id.action_save_db) {
    int permission = ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
    if(permission == PackageManager.PERMISSION_GRANTED) {
        AppDatabase.getInstance(this).getDatabase().close();

        File db = getDatabasePath("my-db");
        File dbShm = new File(db.getParent(), "my-db-shm");
        File dbWal = new File(db.getParent(), "my-db-wal");

        File db2 = new File("/sdcard/", "my-db");
        File dbShm2 = new File(db2.getParent(), "my-db-shm");
        File dbWal2 = new File(db2.getParent(), "my-db-wal");

        try {
            FileUtils.copyFile(db, db2);
            FileUtils.copyFile(dbShm, dbShm2);
            FileUtils.copyFile(dbWal, dbWal2);
        } catch (Exception e) {
            Log.e("SAVEDB", e.toString());
        }
    } else {
        Snackbar.make(mDrawer, "Please allow access to your storage", Snackbar.LENGTH_LONG)
                .setAction("Allow", view -> ActivityCompat.requestPermissions(this, new String[] {
                        Manifest.permission.WRITE_EXTERNAL_STORAGE
                }, 0)).show();
    }
} else if(id == R.id.action_load_db) {
    int permission = ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE);
    if(permission == PackageManager.PERMISSION_GRANTED) {
        AppDatabase.getInstance(this).getDatabase().close();

        File db = new File("/sdcard/", "my-db");
        File dbShm = new File(db.getParent(), "my-db-shm");
        File dbWal = new File(db.getParent(), "my-db-wal");

        File db2 = getDatabasePath("my-db");
        File dbShm2 = new File(db2.getParent(), "my-db-shm");
        File dbWal2 = new File(db2.getParent(), "my-db-wal");

        try {
            FileUtils.copyFile(db, db2);
            FileUtils.copyFile(dbShm, dbShm2);
            FileUtils.copyFile(dbWal, dbWal2);
        } catch (Exception e) {
            Loge("RESTOREDB", e.toString());
        }
    } else {
        Snackbar.make(mDrawer, "Please allow access to your storage", Snackbar.LENGTH_LONG)
                .setAction("Allow", view -> ActivityCompat.requestPermissions(this, new String[] {
                        Manifest.permission.READ_EXTERNAL_STORAGE
                }, 0)).show();
    }
 }

3
投票

作为替代方案,您始终可以创建Room数据库,同时强制它不使用预写日志记录:

Room.databaseBuilder(context, db.class, dbName)
    .setJournalMode(JournalMode.TRUNCATE)
    .build();

0
投票

首先,必须关闭数据库才能应用"dbName.db-wal"文件中的更改。

然后,您可以使用所有表和最后的数据更改来复制数据库

 AppDatabase appDatabase = AppDatabase.getAppDatabase(getApplicationContext());
 appDatabase.close();
© www.soinside.com 2019 - 2024. All rights reserved.