在会议室数据库中调用“插入”无法完成交易

时间:2018-12-11 12:25:41

标签: android kotlin android-room

我在Room数据库中执行简单的@insert操作时遇到了问题。这些是我的课程:

模型类

@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"))

问题是,该操作未持久存储在db文件中。如果我进入databases文件夹,则有一个mydb文件,一个wal和一个shm文件,并且在mydb中没有创建表。 但是,如果我在插入操作之后调用db?.close(),则该操作将按其应有的方式发生(已创建并填充了表),并且walshm文件不存在。

我在这里想念什么?我很确定我不必在数据库上调用close()。我试过使用beginTransaction()endTransaction()调用来包围插入调用,以查看它是否进行了更改,但是没有更改。

更新: 正如@musooff在评论中解释的那样,显然这就是sqlite dbs的工作方式。即使文件本身看起来是空的,我也要在插入调用以及返回的记录之后查询数据库。

1 个答案:

答案 0 :(得分:3)


TL; DR

您的代码似乎运行正常。不要为SQLite创建的临时文件感到困惑。

  1. WAL和SHM文件是您不需担心的临时内部文件。
  2. 如果要直接检查db文件来检查是否存在数据,则该数据可能还不存在。等待直到关闭连接。
  3. 使用SQLiteBrowser查看数据是否存在。您可以检查SQLiteBrowserAndroid Debug Database
  4. 除了使用SQLiteBrowser之外,您还可以使用SELECT查询简单地检查是否存在来自Android应用程序的数据。

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文件会自动删除。 (More here)

交易未立即写入数据库文件

  

传统的回滚日志的工作原理是将原始未更改的数据库内容的副本写入单独的回滚日志文件,然后将更改直接写入数据库文件。如果发生崩溃或ROLLBACK,则回滚日志中包含的原始内容会被回放到数据库文件中,以将数据库文件还原为原始状态。删除回退日志时,将发生COMMIT。

     

WAL的方法可以扭转这种情况。原始内容保留在   数据库文件和更改将附加到单独的WAL中   文件。当表示提交的特殊记录为   附加到WAL。 因此,无需写信即可进行COMMIT   原始数据库,使读者可以继续从   原始未更改的数据库,同时进行更改   承诺加入WAL 。可以将多个事务附加到   一个WAL文件的结尾。

     

当然,最终希望将WAL文件中附加的所有事务转移回原始数据库中。   将WAL文件事务移回数据库称为   “检查点”。

     

默认情况下,当WAL文件出现时,SQLite自动执行一个检查点   达到1000页的阈值大小。 (   SQLITE_DEFAULT_WAL_AUTOCHECKPOINT编译时选项可用于   指定不同的默认值。)使用WAL的应用程序不必这样做   为了使这些检查点发生而进行的任何操作。但是如果他们想要   到此,应用程序可以调整自动检查点阈值。要么   他们可以关闭自动检查点并在运行期间运行检查点   空闲时刻或在单独的线程或进程中。 (More here)

SHM 只是与WAL机制相关的临时共享内存文件,其唯一目的是:

  

共享内存文件不包含任何持久性内容。共享内存文件的唯一目的是提供一块共享内存,供所有在WAL模式下访问同一数据库的多个进程使用。 (More here)