我的perl脚本是多线程的,在每个线程中我都要写一些东西到sqlite3数据库。但正如你可能猜到的那样,我得到了很多
DBD :: SQLite :: db失败:数据库在script.pl第264行被锁定。
消息。我读到sqlite3能够处理多线程情况,甚至是INSERT语句,但我认为在同时插入8个线程时我会期待很多。
好的,所以不可能这样,但是在插入之前是否有可能执行检查以查看数据库是否已锁定(或忙碌)然后等待再次免费?
我真的不想改成“真正的”DBMS,因为它只是一个简单的脚本。
谢谢
答案 0 :(得分:6)
如果您需要阻止,直到可以访问数据库,请尝试独占交易,即
$dbh->do("begin exclusive transaction") or die $dbh->errstr;
#inserts here
$dbh->do("commit transaction") or die $dbh->errstr;
这样,您将锁定委托给SQLite,而不是在Perl中进行。由于各种原因,这样更安全,尤其是您可能在Perl之外的其他内容中打开数据库,或者在另一个Perl进程而不是线程中打开数据库。
而且,正如@mob评论的那样,Perl线程是一个有点可笑的野兽。我只是得到数据库所做的锁定。
答案 1 :(得分:2)
当写入数据库时,SQLite使用fcntl()锁定整个数据库文件。当另一个进程/线程尝试写入它时,它将等待一段时间(30秒?)然后放弃。请参阅SQLiteFAQ。
请注意,虽然Perl的线程确实很麻烦且很奇怪,但这不是根本问题。我认为除了最简单的需求之外,SQLite是一个不合适的选择。
答案 2 :(得分:1)
一种替代方法可能是将每个线程插入到自己的临时表中,然后对变量使用lock
(虚拟变量很好)并在线程具有锁定时插入到最终表中。换句话说,就像......
sub ThreadStuff
{
my $tid=threads->tid;
#Thread is doing whatever it's doing
$dbh->do("delete from staging_" . $tid) or die $dbh->errstr;
$dbh->do("insert into staging_" . $tid . "stuff;") or die $dbh->errstr;
{
lock $hall_pass;
$dbh->do("insert into final_table select * from staging_" . $tid) or die $dbh->errstr;
#The lock on $hall_pass goes away as soon as we leave this block.
}
#Other stuff, maybe cleanup or whatever.
}