我正在尝试以编程方式备份房间数据库。
为此,我只是复制包含整个数据库的.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()
对象上的RoomDatabase
在true
之前返回INSERT
房间版:1.1.1-rc1
关闭后如何才能正确地重新打开房间数据库?
对不起,我对这个问题没有答案。
但是将所有内容移动到原始数据库文件是您要执行的操作,然后您不必关闭数据库。您可以使用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
的作用。
为了更具体地回答您的问题,这是我在我的一个应用程序中备份房间数据库的方式。
RoomDatabase
。在我的例子中,AppDatabase
指的是包含最初构建房间数据库的逻辑的单例。 AppDatabase.getInstance(this).getDatabase()
获取单例的当前实例,以及从RoomDatabase
扩展的当前数据库类。这基本上叫RoomDatabase.close()
。FileUtils
指的是commons-io
。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();
}
}
作为替代方案,您始终可以创建Room数据库,同时强制它不使用预写日志记录:
Room.databaseBuilder(context, db.class, dbName)
.setJournalMode(JournalMode.TRUNCATE)
.build();
首先,必须关闭数据库才能应用"dbName.db-wal"
文件中的更改。
然后,您可以使用所有表和最后的数据更改来复制数据库
AppDatabase appDatabase = AppDatabase.getAppDatabase(getApplicationContext());
appDatabase.close();