База данных резервных копий
Я пытаюсь сделать резервную копию базы данных комнаты программно.
Для этого я просто .sqlite
файл .sqlite
который содержит всю базу данных
Но, перед копированием, из - за того, что помещение имеет упреждающее журналирование включено, мы должны закрыть базу данных, так что -shm
файл и -wal
файл сливаются в единый .sqlite
файл. Как указано здесь
Я запустил .close()
в объекте RoomDatabase
:
Все работает отлично с резервным копированием, НО, позже, когда я пытаюсь выполнить запрос INSERT
, я получаю эту ошибку:
android.database.sqlite.SQLiteException: no such table: room_table_modification_log (code 1)
Как я могу правильно заново открыть комнату db после ее закрытия?
PS: .isOpen()
на объекте RoomDatabase
возвращает true
до INSERT
Версия комнаты: 1.1.1-rc1
Ответы
Ответ 1
Как я могу правильно открыть комнату БД после закрытия?
Мне жаль, что у меня нет ответа на этот вопрос.
Но если вы хотите переместить все в исходный файл базы данных, вам не нужно закрывать базу данных. wal_checkpoint
этого вы можете форсировать контрольную точку, используя прагму wal_checkpoint
.
Запросите следующее утверждение к базе данных. Здесь мы используем необработанные запросы, так как Room еще не поддерживает pragma
(она вызовет ошибку UNKNOWN query type
). Имейте этот запрос внутри вашего DAO:
@RawQuery
int checkpoint(SupportSQLiteQuery supportSQLiteQuery);
И затем, когда вы вызываете метод контрольной точки, используйте запрос затем:
myDAO.checkpoint(new SimpleSQLiteQuery("pragma wal_checkpoint(full)"));
Эта ссылка может пролить некоторый свет на то, что делает wal_checkpoint
.
Ответ 2
Чтобы более точно ответить на ваш вопрос, так я резервирую базу данных в одной из моих приложений.
- Проверьте разрешение на чтение/запись во внешнюю память. Этот шаг можно проигнорировать, если вы пишете в своем каталоге файлов приложений.
- Закройте свою
RoomDatabase
. В моем случае AppDatabase
ссылается на синглтон, содержащий AppDatabase
логику для создания базы данных комнаты. AppDatabase.getInstance(this).getDatabase()
получает текущий экземпляр singleton и его текущий класс базы данных, который выходит из RoomDatabase
. Это по существу вызывает RoomDatabase.close()
. - Определите исходный и целевой файлы, в зависимости от резервного копирования или восстановления. Я включаю файлы shm и wal, хотя это временные файлы.
- Скопируйте файлы с помощью выбранного вами метода.
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();
}
}
Ответ 3
В качестве альтернативы вы всегда можете создать свою базу данных в комнате, не заставляя ее не использовать запись на запись вперед:
Room.databaseBuilder(context, db.class, dbName)
.setJournalMode(JournalMode.TRUNCATE)
.build();
Ответ 4
Во-первых, база данных должна быть закрыта, чтобы применить изменения из "dbName.db-wal"
.
Затем вы можете скопировать базу данных со всеми таблицами и последними изменениями данных
AppDatabase appDatabase = AppDatabase.getAppDatabase(getApplicationContext());
appDatabase.close();
Ответ 5
Как правильно открыть базу данных после копирования файла? Я открываю его в AppModule следующим образом:
@Singleton
@Provides
fun provideDb(app: Application): FastcountDb {
val db: FastcountDb = Room.databaseBuilder(app, FastcountDb::class.java, AppConfig.DB_NAME + ".db")
.fallbackToDestructiveMigration()
.setJournalMode(RoomDatabase.JournalMode.TRUNCATE)
.build()
return db
}