Jetpack Room(扩展)

1,249 阅读2分钟

这是我参与11月更文挑战的第8天,活动详情查看:2021最后一次更文挑战

Transaction

Transaction是一个数据库概念,一般称之为「事务」。它的属性有四个:原子性(Atomicity)一致性(Consistency)隔离性(Isolation)持久性(Durability) ,缩写为ACID。

原子性是指:一个事务中做的任意多个操作就像是一个操作,要么成功,要么失败。成功表示所有操作执行完成,失败表示有的操作有些问题,失败后系统会将数据库状态回退到执行事务之前。利用这个属性可以很简单的解决数据库的读写冲突问题。

一致性是指:数据库在成功提交的事务上会正确地改变状态。

隔离性是指:事务的操作会相互独立和透明。这一点在Room中被屏蔽掉了,因为Room 一次最多只能执行一个事务,其他事务按先到先得的顺序排队和执行。

持久性是指:确保已提交事务的结果或效果在系统发生故障的情况下仍然存在。

实际上@Insert,@Update和@Delete是事务,以及在@Query中使用了Insert,Update或者Delete,这个@Query也是默认被@Transaction标注的。

这样的话,如果你的某个事务是比较耗时的,那你执行其他时候就得排队咯。

不过,你也可以利用这个特性,将一系列操作整合到一个事务中,例如一个先查再改再查的操作(以下是伪代码):

@Transaction
fun someOperation():Int{
    val a = find1()
    insert(a)
    return find2()
}

事务和协程的取舍

事务中的代码应专注于对纯 SQL 的拼接,需要先查数据再对数据进行处理处理后的在执行SQL的场景还是得用协程。

@Transaction保证了原子性,但会在执行事务时一直持有着Sqlite实例,期间任何 SQL 都没法操作。

而协程并不会持续地持有着Sqlite实例,但需要开发者自己对函数的原子性进行处理。

注:大概在2.2.6之后@Transaction函数前不能加suspend了,因为这样导致多个线程同时读写sqlite,导致死锁。

优化首次查询速度

第一次查询会慢一些,不管是一条还是 3000 条,其实可能大概需要 200ms 左右,这是 SQLite 的局限性...

解决方案:在客户无感知的时候先热启动 Sqlite 先查一条。

FTS不可用

不论是FTS3还是FTS4的特性在 Room 中都没法使用。