База данных комнат Android не экспортирует все данные

Я пытаюсь настроить функцию резервного копирования базы данных комнаты. Проблема в том, что файл базы данных sql не содержит последнего набора данных в приложении после загрузки. Он всегда пропускает самые свежие записи. Есть ли правильный способ экспортировать базу данных комнат? P.S. Я не сталкивался с подобными проблемами, когда обрабатывал свою базу данных с помощью sqliteHelper, поэтому я полагаю, что это должно иметь какое-то отношение к Room.

Как я это делаю:

@Throws(IOException::class)
private fun copyAppDbToDownloadFolder(address: String) {
    val backupDB = File(address, "studioDb.db") 
    val currentDB = applicationContext.getDatabasePath(StudioDatabase.DB_NAME)
    if (currentDB.exists()) {
        val src = FileInputStream(currentDB).channel
        val dst = FileOutputStream(backupDB).channel
        dst.transferFrom(src, 0, src.size())
        src.close()
        dst.close()
    }
}

также обновлять при запуске резервного копирования

Lokesh 13.04.2018 19:39

попробуйте этот stackoverflow.com/questions/44986465/… надеюсь, что это поможет вам

Lokesh 13.04.2018 19:41

Попробуйте это.

Bertram Gilfoyle 29.07.2018 06:05

вы должны закрыть свою базу данных перед ее копированием, попробуйте этот stackoverflow.com/a/53976242/4858757

Shahab Saalami 30.12.2018 09:48
10
4
5 389
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Ответ принят как подходящий

Я решил это. При экспорте (сохранении) базы данных sql, которую вы обрабатываете с помощью Room, вам необходимо экспортировать (а затем импортировать) оба файла - your_database.bd и your_database.wal. Позже ведется журнал, а афайу ведет последние записи.

каков путь к обоим файлам, пожалуйста, объясните, у меня такая же проблема

Lokesh 18.04.2018 19:22

@Lokesh Есть несколько способов получить путь к базе данных. Я использую следующее: val currentDBPath = "//data//" + packageName + "//databases//" + DatabaseHelper.DATABASE_NAME + "" val backupDBPath = DatabaseHelper.DATABASE_NAME + ".db" val currentDB = File(data, currentDBPath)

Tuesday Four AM 19.04.2018 20:06

Другой подход заключается в следующем (обратите внимание, что я использую его для получения пути к файлу .wal): val currentdbW = applicationContext.getDatabasePath(StudioDatabase.DB_NAME + "-wal")

Tuesday Four AM 19.04.2018 20:10

У меня была такая же проблема. Вам не нужно копировать wal (файл журнала упреждающей записи), это временный файл. Согласно документация нам необходимо закрыть все соединения с базой данных перед импортом или экспортом базы данных. Это решило мою проблему, и теперь мне нужно скопировать только основной файл базы данных.

Пример класса базы данных:

public abstract class AppDB extends RoomDatabase {    

    private static final Object sLock = new Object();

    private static AppDB INSTANCE;

    // create new database connection
    public static AppDB getInstance(final Context context) {
        synchronized (sLock) {
            if (INSTANCE == null) {
                INSTANCE = Room.databaseBuilder(context.getApplicationContext(), AppDB.class, "packagename")                    
                    .build();
                }
            return INSTANCE;
        }
    }

    // close database
    public static void destroyInstance(){
        if (INSTANCE.isOpen()) INSTANCE.close();
        INSTANCE = null;
    }
}

Спасибо, это отличная новость! А как именно закрыть все подключения к базе данных?

Tuesday Four AM 18.05.2018 12:46

просто вызовите функцию close () для всех объектов базы данных вашей комнаты.

Muzammil Husnain 18.05.2018 14:42

@MuzammilHusnain "все объекты базы данных вашей комнаты" Должен быть только один экземпляр открытой базы данных.

rupinderjeet 24.05.2018 05:56

@rupinderjeet да, в идеале должен быть только один экземпляр открытой базы данных.

Muzammil Husnain 24.05.2018 11:57

Проблема в том, что если вы повторно откроете базу данных и попытаетесь выполнить что-либо, это не удастся, как объясняется здесь: stackoverflow.com/questions/50987119/backup-room-database

Marco HC 26.07.2018 09:28

Идея действительно полезна, вам нужно закрыть базу данных, тогда исходную базу данных можно скопировать или создать резервную копию.

Chanh 26.07.2019 10:50

Вам нужно использовать

JournalMode.TRUNCATE

в вашем AppDatabase.java:

private static AppDatabase sInstance;

public static AppDatabase getDatabase(final Context context) {
    if (sInstance == null) {
        synchronized (AppDatabase.class) {
            if (sInstance == null) {
                sInstance = Room.databaseBuilder(context, AppDatabase.class, DATABASE_NAME)
                        .setJournalMode(JournalMode.TRUNCATE)
                        .build();
            }
        }
    }
    return sInstance;
}

Этот метод не будет создавать файлы db.bad и db.wal, которые создают препятствия при экспорте базы данных комнаты.

Для экспорта файла БД:

Link: Exporting db with creating folder on daily basis

Котлин: Это работает для меня

private fun exportDb() {
    val TABLE_NAME = "order_table"

    val exportDir = File(getExternalStorageDirectory(), "/CSV")// your path where you want save your file
    if (!exportDir.exists()) {
        exportDir.mkdirs()
    }

    val file = File(exportDir, "$TABLE_NAME.csv")


    try {
        file.createNewFile()
        val db: MenuItemsDatabase = MenuItemsDatabase.getDatabase(requireActivity())
        val csvWrite = CSVWriter(FileWriter(file))
        val curCSV: Cursor = db.query("SELECT * FROM order_table", null)
        csvWrite.writeNext(curCSV.getColumnNames())
        while (curCSV.moveToNext()) {
            //Which column you want to exprort
               val arrStr = arrayOfNulls<String>(curCSV.getColumnCount())
        
            for (i in 0 until curCSV.getColumnCount() - 1) arrStr[i] = curCSV.getString(i)
            csvWrite.writeNext(arrStr)
        }
        csvWrite.close()
        curCSV.close()
        Toast.makeText(context, "Exported", Toast.LENGTH_SHORT).show()

    } catch (sqlEx: java.lang.Exception) {
        //Log.e("Payment fragment", "Exported error", sqlEx)
        Toast.makeText(context, "Exported error", Toast.LENGTH_SHORT).show()
    }
}

Другие вопросы по теме