Вызов 'insert' в базе данных комнаты не завершает транзакцию - PullRequest
0 голосов
/ 11 декабря 2018

У меня проблема с простой операцией @insert в базе данных Room.Вот мои классы:

Класс модели

@Entity(tableName = "my_model")
data class MyModel(
    @PrimaryKey @ColumnInfo(name = "id_model") var uid: Int,
    @ColumnInfo(name = "name") var firstName: String,
    @ColumnInfo(name = "last_name") var lastName: String
)

Интерфейс DAO

interface MyModelDAO {
    @Insert
    fun createMyModel(myModel: MyModel)
}

База данных

@Database(
    entities = [(MyModel::class)],
    version = 1,
    exportSchema = false
)
abstract class MyDb : RoomDatabase() {

    companion object {
        private var INSTANCE: MyDb? = null

        fun getInstance(context: Context): MyDb? {
            if (INSTANCE == null) {
                synchronized(MyDb::class) {
                    INSTANCE = Room.databaseBuilder(context.applicationContext,
                        MyDb::class.java, "mydb.db")
                        .allowMainThreadQueries()//for testing purposes only
                        .build()
                }
            }
            return INSTANCE
        }

        fun destroyInstance() {
            INSTANCE = null
        }
    }


    abstract fun getMyModelDao(): MyModelDAO
}

И вот какЯ пытаюсь вставить объект.

val db = MinhaDb.getInstance(this)
db?.getMyModelDao()?.createMyModel(MyModel(111, "john", "doe"))

Дело в том, что операция не сохраняется в файле базы данных.Если я захожу в папку databases, то есть файл mydb, файл wal и shm, и в mydb не создаются таблицы.Тем не менее, если я вызываю db?.close() после операции вставки, операция происходит так, как она должна (таблица создается и заполняется), а файлы wal и shm отсутствуют.

Что такоеЯ здесь скучаю?Я почти уверен, что мне не нужно было вызывать close() в базе данных.Я попытался окружить вызов вставки вызовами beginTransaction() и endTransaction(), чтобы посмотреть, изменился ли он, но это не произошло.

ОБНОВЛЕНИЕ: Как объяснил @musooffв комментариях, видимо, так работает sqlite dbs.Я запросил базу данных после вызовов вставки и, действительно, записи, которые были возвращены, даже если сам файл кажется пустым.

1 Ответ

0 голосов
/ 11 декабря 2018

TL; DR

Ваш код работает нормально.Не путайтесь с временными файлами, которые SQLite создает для работы.

  1. Файлы WAL и SHM являются временными внутренними файлами, о которых вам не следует беспокоиться.
  2. Если вы проверяетеесли данные присутствуют при непосредственном рассмотрении файла db, данные могут еще не быть там.Подождите, пока вы закроете соединение.
  3. Используйте SQLiteBrowser, чтобы увидеть, есть ли данные или нет.Вы можете проверить SQLiteBrowser или База данных отладки Android
  4. Вместо использования SQLiteBrowser, вы можете просто проверить, присутствуют ли данные из вашего приложения Android, с помощью запроса SELECT.

WAL и SHM файлы

Как вы заметили, в вашем каталоге db вы можете найти три сгенерированных файла:

your-database-name
your-database-name-shm
your-database-name-wal

Тем не менее, единственное важное значение для вас, где на самом деле находятся данные, это your-database-name.

Файл wal используется вместо Rollback Journal .

Начиная с версии 3.7.0 (2010-07-21), SQLite поддерживает новый механизм управления транзакциями, который называется «журнал записи» или «WAL».Когда база данных находится в режиме WAL, все соединения с этой базой данных должны использовать WAL.Конкретная база данных будет использовать либо журнал отката, либо WAL, но не оба одновременно.WAL всегда находится в том же каталоге, что и файл базы данных, и имеет то же имя, что и файл базы данных, но с добавленной строкой «-wal».

То, что вы упоминаете о невозможности увидетьданные в файле вашей базы данных, пока файл wal все еще там, и затем вы закрываете соединение, и файл wal исчезает, и данные, наконец, сохраняются в базе данных, - правильное поведение при использованииwal механизм.

WAL исчезает

Файл WAL существует до тех пор, пока любое соединение с базой данных имеет открытую базу данных.Обычно файл WAL удаляется автоматически при закрытии последнего подключения к базе данных. (Подробнее здесь)

Транзакция не записывается немедленно в файл базы данных

Традиционный журнал отката работает путем записископировать исходное неизмененное содержимое базы данных в отдельный файл журнала отката, а затем записать изменения непосредственно в файл базы данных.В случае сбоя или ROLLBACK исходное содержимое, содержащееся в журнале отката, воспроизводится в файле базы данных, чтобы вернуть файл базы данных в исходное состояние.COMMIT происходит при удалении журнала отката.

Подход WAL инвертирует это.Исходный контент сохраняется в файле базы данных, а изменения добавляются в отдельный файл WAL.COMMIT происходит, когда к WAL добавляется специальная запись, указывающая на фиксацию. Таким образом, COMMIT может происходить без записи в исходную базу данных, что позволяет читателям продолжать работу с исходной неизмененной базы данных, пока изменения одновременно вносятся в WAL .Несколько транзакций могут быть добавлены в конец одного файла WAL.

Конечно, в конечном итоге требуется перенести все транзакции, добавленные в файл WAL, обратно в исходную базу данных. Перемещение транзакций файла WAL обратно в базу данных называется «контрольной точкой».

По умолчанию SQLite автоматически выполняет контрольную точку, когда файл WAL достигает порогового размера 1000 страниц..(Параметр времени компиляции SQLITE_DEFAULT_WAL_AUTOCHECKPOINT можно использовать для указания другого значения по умолчанию.) Приложениям, использующим WAL, не нужно ничего делать, чтобы эти контрольные точки выполнялись .Но если они хотят, приложения могут настроить автоматический порог контрольной точки.Или они могут отключить автоматические контрольные точки и запускать контрольные точки во времямоменты простоя или в отдельном потоке, или в процессе. (Подробнее здесь)

SHM - это просто временный файл общей памяти, связанный с механизмом WAL, единственное назначение которого:

Файл общей памяти не содержит постоянного содержимого.Единственная цель файла с разделяемой памятью - предоставить блок разделяемой памяти для использования несколькими процессами, обращающимися к одной и той же базе данных в режиме WAL. (Подробнее здесь)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...