我在Android项目中使用ORMLite。我知道Sqlite负责文件级锁定。很多线程都可以读,有人可以写。锁可防止多次写入。 有人可以解释一下,如果一个线程正在更新某个记录而另一个线程正在尝试读取该记录,会发生什么?线程(试图读取)会得到过时的数据吗?或者它会被锁定,直到第一个线程完成其写操作? 据我所知,有4个事务隔离级别:Serializable,Repeatable read,Read committed,Read uncommitted。有没有办法在SQLite或ORMLite中更改它?
答案 0 :(得分:9)
SQLite有5种不同的锁定级别 - http://www.sqlite.org/lockingv3.html: 解锁,共享,保留,待定,独占。 这个问题的重要锁定是共享锁:
“共享 - 数据库可能被读取但未被写入。任意数量的数据库 进程可以同时保存SHARED锁,因此可以 许多同时读者。但是不允许其他线程或进程 在一个或多个SHARED锁定时写入数据库文件 活性“。
锁是表级的(因此在DB中使用单行执行某些操作时 - 整个表都被锁定)。
因此,在选择数据时,不允许其他进程更改数据。 读取数据的锁定步骤为:UNLOCKED→PENDING→SHARED→UNLOCKED(您可以在事务中运行选择)。因此,您选择某些内容并且有人会改变数据的情况不会发生。
您的问题是如果您要更新数据库并在同一个表上执行选择会发生什么。在自动提交模式下,写入/更新的锁定机制是: 已解锁→待处理→共享→已保留→待处理→已排除→已解锁。 在Exclusive锁中,没有新的读者(连接)可以连接到数据库。一次只能存在一个EXCLUSIVE锁。然后SQLite将等待,直到读取连接的所有其他PENDING锁被释放,并将阻止任何新的。此时,它将开始写入数据。
所以,我的答案是 - 只要更新过程没有完成,你的其他过程当然会获得旧数据。确保在事务中运行更新,以便不会发生数据不一致。 SQLite符合ACID标准,因此不会发生部分更新和包含数据的情况。
一本关于此的好书是“SQLite的权威指南”,特别是交易章节。
答案 1 :(得分:3)
SQLite支持几种不同的隔离级别,可在编译时和运行时选择。
我认为默认情况下Android的SQLite处于 Serialized 模式。在多线程访问方面,它在文件系统级别进行读/写锁定,以允许多个读取器,但一次只允许一个写入器:
但是,ORMLite建议强烈并尝试硬来维护与数据库的单一连接,以便锁定问题可能不相关。
更具体地说,如果一个线程正在更新记录而另一个线程正在读取,那么它就是竞争条件。读取线程将在更新之前或更新完成之后获取记录。但是,读者不会获得部分更新的数据。但我怀疑你知道这一点。
就SQLite支持的隔离级别而言,默认为 Serialized ,如上所述,但看起来它至少在某种程度上支持 read-uncommitted 。
您可以使用ORMLite的Dao.executeRaw()方法启用它:
dao.executeRaw("PRAGMA read_uncommitted = True;");
但是,我对此没有任何经验,也不确定如果在同一查询中多次访问该行,它是否会为您提供更新行的一致视图。在写入事务期间,它可能与更一致的视图有关。
在阅读this similar question之后,如果在同一查询中多次访问该行,我不确定是否可以保证表中某行的相同视图。