当使用Perl的DBD :: SQLite时,为什么SQLite为事务中的第二个查询提供“数据库被锁定”?

时间:2010-10-15 14:54:38

标签: perl sqlite prepared-statement dbi dbd

使用Perl DBD :: SQLite时,SQLite是否存在已知问题,在单个事务中为第二个查询提供“数据库已锁定”错误?场景:Linux,Perl DBI,AutoCommit => 0,一个带有两个代码块的子程序(使用块来本地化变量名)。在第一个代码块中,一个查询句柄由select()在select语句中创建,它被执行()并且块被关闭。第二个代码块是通过准备更新语句创建的另一个查询句柄,并且经常(30%的时间)SQLite / DBI在此阶段给出数据库锁定错误。我认为错误发生在prepare()期间而不是在execute()期间。

我的工作是在第一次查询后提交。 (在第一个查询上调用完成没有帮助)。我不喜欢有几个与优雅和表现有关的理由。 Postgres作为数据库,原始代码已经运行了很多年。我尝试了sqlite_use_immediate_transaction没有效果。

在所有其他情况下,我发现SQLite的表现非常好,所以我怀疑这是DBD驱动程序中的疏忽,而不是SQLite的问题。遗憾的是,我目前的代码是一大堆脚本和模块,因此我没有简短的单个文件测试用例。

1 个答案:

答案 0 :(得分:7)

无论如何都是这样的:来自Transaction and Database Locking perldoc的DBD::SQLite

  

通过AutoCommit或begin_work进行的交易非常方便,但有时您可能会遇到恼人的“数据库被锁定”错误。这通常发生在某人开始交易时,并尝试在其他人从数据库读取时(在另一个事务中)写入数据库。您可能会感到惊讶,但是当您刚开始正常(延迟)事务以最大化并发时,SQLite不会锁定数据库。它在您发出要写入的语句时保留锁定,但在您实际尝试使用commit语句编写之前,它允许其他人从数据库中读取。但是,从数据库中读取也需要共享锁定,这会阻止您提供您保留的独占锁定,从而导致“数据库被锁定”错误,如果他们之后尝试写入,则其他人将收到相同的错误,如你还有一个待定的锁。 busy_timeout在这种情况下无效。

     

为避免这种情况,请明确设置事务类型。您可以为每个事务发出begin immediate事务(或开始独占事务),或者将sqlite_use_immediate_transaction数据库句柄属性设置为true(从1.30_02开始)以始终使用立即事务(即使您只是使用begin_work或关闭AutoCommit。)

my $dbh = DBI->connect("dbi:SQLite::memory:", "", "", {
  sqlite_use_immediate_transaction => 1,
});
  

请注意,仅当所有连接使用相同(非延迟)事务时,此方法才有效。有关锁定详情,请参阅http://sqlite.org/lockingv3.html

相关问题