根据文档关于延迟赎回的规定:
默认事务行为被推迟。(...)对数据库的第一读操作创建共享锁,第一写入操作创建保留锁。
此外,根据锁上的文档:
任意数量的进程都可以同时持有共享锁(.)一次可能只有单个保留锁处于活动状态,尽管多个共享锁可以与单个保留锁共存。
这听起来像是具有任意读取器到写入器的多个读取器/单个写入器锁,这是已知的死锁危险:
那么SQLite是如何绕过这个问题的呢?我想到了两种可能的解决方案,但这两种解决方案似乎都打破了整个交易的想法:
我是不是遗漏了什么?SQLite是如何处理这个问题的?为什么这种看似危险的交易是默认的呢?
发布于 2019-04-24 15:49:21
通过简单的尝试和错误,我发现他们走了错误的路线.
在给定的场景中,当B尝试保留时,它将首先等待PRAGMA busy_timeout
毫秒。然后它将报告Error: database is locked
。事务仍将处于活动状态,因此可以立即重试。
如果A随后尝试COMMIT
(或者如果内存中缓存用完了),它将接受挂起的锁(防止额外的共享锁),然后等待独占。如果某些共享锁在PRAGMA busy_timeout
毫秒后仍然存在,它将报告错误:数据库被锁定。事务仍将处于活动状态,因此可以立即重试。
换句话说,所使用的死锁预防机制是超时。但是,它确实要求API用户通过回滚和再次尝试来进行协作。
作为指导方针:
BEGIN TRANSACTION
(或显式BEGIN DEFERRED TRANSACTION
)当您只希望阅读。写入可能会失败,迫使您回滚并再次重试整个事务。BEGIN IMMEDIATE TRANSACTION
。这将阻止所有其他作家和所有其他直接的作家。BEGIN EXCLUSIVE TRANSACTION
将立即阻塞,直到释放所有其他锁为止。我不知道为什么会有人想要这个。可能是为了准备一些需要在数据到达磁盘后尽快写入磁盘的数据?编辑:,这似乎是在事务开始后防止任意点超时的唯一方法。https://stackoverflow.com/questions/55831645
复制相似问题