Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sqlite/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
SQLite如何防止延迟事务的死锁?_Sqlite - Fatal编程技术网

SQLite如何防止延迟事务的死锁?

SQLite如何防止延迟事务的死锁?,sqlite,Sqlite,根据关于递延赎金的规定: 默认事务行为被延迟。(…)对数据库的第一次读取操作将创建共享锁和 第一次写入操作创建一个保留锁 此外,根据打开的锁: 任意数量的进程可以同时持有共享锁(…) 一次只能激活一个保留锁,尽管有多个 共享锁可以与单个保留锁共存 这听起来像是带有任意读写器升级机制的多读写器/单写器锁,这是一种已知的死锁危险: 开始交易 B开始交易 获取共享锁并读取某些内容 B获取共享锁并读取某些内容 A获得保留锁并准备写入某些内容。只要存在其他共享锁,它就无法写入,因此会阻塞 B希望写,所以

根据关于递延赎金的规定:

默认事务行为被延迟。(…)对数据库的第一次读取操作将创建共享锁和 第一次写入操作创建一个保留锁

此外,根据打开的锁:

任意数量的进程可以同时持有共享锁(…) 一次只能激活一个保留锁,尽管有多个 共享锁可以与单个保留锁共存

这听起来像是带有任意读写器升级机制的多读写器/单写器锁,这是一种已知的死锁危险:

  • 开始交易
  • B开始交易
  • 获取共享锁并读取某些内容
  • B获取共享锁并读取某些内容
  • A获得保留锁并准备写入某些内容。只要存在其他共享锁,它就无法写入,因此会阻塞
  • B希望写,所以尝试使用保留锁。已经有另一个保留锁,因此它会阻塞,直到释放为止,但仍保留共享锁
  • 僵局
那么SQLite如何解决这个问题呢?我想到了两种可能的解决方案,但它们似乎都打破了交易的整体理念:

  • 可能是写入程序在获取保留前释放共享锁。这将打破读写之间的原子性
  • B在尝试获取保留锁时不阻塞,但会出错。这意味着所有的读取都需要重复,这会使API的使用变得非常复杂

我错过什么了吗?SQLite如何处理这个问题?为什么这种看似危险的事务会成为默认类型?

通过简单的尝试和错误,我发现他们排除了错误

在给定的场景中,当B尝试保留时,它将首先等待
PRAGMA busy\u timeout
毫秒。然后它将报告
错误:数据库已锁定
。事务仍将处于活动状态,因此可以立即重试

如果AFTER尝试提交(或者如果内存缓存中的内存不足),它将获取挂起的锁(防止额外的共享锁),然后等待独占。如果在
PRAGMA busy_timeout
毫秒后仍有一些共享锁,它将报告错误:数据库已锁定。事务仍将处于活动状态,因此可以立即重试

换句话说,使用的死锁预防机制是超时。但是,它确实需要API用户通过回滚并重试来进行合作

作为一项准则:

  • 当您只希望阅读时,只需使用
    begintransaction
    (或明确地使用
    begindeferredtransaction
    )。写入可能会失败,迫使您回滚并再次重试整个事务
  • 当您希望在某个时候进行写操作时,请使用
    立即开始事务处理。这将阻止所有其他编剧和所有其他直接编剧
  • 开始独占事务
    将立即阻止,直到释放所有其他锁。我不知道为什么会有人想要这个。可能是为了准备一些数据,这些数据需要在到达后尽快写入磁盘编辑:这似乎是防止事务开始后在任意点超时的唯一方法

您忘记了解决挂起锁的使用问题,这通常会打破死锁的情况。@MarkBenningfield确切地说是什么?这只是向独家的过渡。在我的示例场景中,从技术上讲,在阻塞之前从保留状态转换为挂起状态,直到可以转换为独占状态。@MarkBenningfield AFAIK,PENDING只解决了在遇到大量读卡器时写入器饥饿的问题,而不是死锁。