DBD :: SQLite:数据库被锁定:如何重试?

时间:2016-12-14 13:10:31

标签: perl sqlite dbi

我并行使用SQLite数据库。主要是阅读 - 这意味着一切都很好。但也用于写和删除表。然后突然间我随机得到这个(这表明竞争条件 - 预计并行运行):

Error: near line 1: database is locked

现在我知道在10毫秒内数据库将不会被锁定,所以我想等待10毫秒再试一次,但我找不到捕获该错误的方法。

如何捕获该错误?

1 个答案:

答案 0 :(得分:0)

更新

请注意上面的Georg Mavridis' comment

听起来您的子进程正在共享相同的数据库连接并相互锁定

如果您想要真正的并行性,那么您需要与数据库建立多个连接。 SQLite将对来自不同连接的请求进行排队,并为您解决冲突,除非该行为被禁用。


您需要设计DBI应用程序的错误处理。 connect调用

中可以指定三个选项
  • PrintError - 默认情况下已启用 - 如果出现错误,将导致发出警告

  • RaiseError - 默认关闭 - 如果出现错误,这将导致进程死亡

  • HandleError - 默认情况下未设置 - 此选项必须设置为子例程引用,如果出现错误,将调用该子例程

如果您不希望出现数据库错误,那么最好使用

my $dbh = DBI->connect( ..., { PrintError => 0, RaiseError => 1 } )

然后,您可以为可能出错的代码部分启用错误处理,并且您想尝试修复它

DBI documentation for the RaiseError option说明了这个

  

如果你想暂时关闭RaiseError(例如,在可能失败的库函数中),建议的方法是这样的:

{
  local $h->{RaiseError};  # localize and turn off for this block
  ...
}

这样,RaiseError选项在右大括号中被隐式重新打开,在块中你可以检查execute返回的值,它表示操作是否成功,以及{ {1}},它提供了持续错误类型的详细信息。然后,您可以在Perl中编写重试代码以执行任何操作

标准errstr调用将暂停进程,但粒度为一秒。如果您的程序在重试之间等待很长时间,那么请查看Time::HiRes模块中的sleep函数,该函数需要1微秒的倍数