sqlite中多线程INSERTS的限制

时间:2011-07-11 15:50:59

标签: perl sqlite

我的perl脚本是多线程的,在每个线程中我都要写一些东西到sqlite3数据库。但正如你可能猜到的那样,我得到了很多

  

DBD :: SQLite :: db失败:数据库在script.pl第264行被锁定。

消息。我读到sqlite3能够处理多线程情况,甚至是INSERT语句,但我认为在同时插入8个线程时我会期待很多。

好的,所以不可能这样,但是在插入之前是否有可能执行检查以查看数据库是否已锁定(或忙碌)然后等待再次免费?

我真的不想改成“真正的”DBMS,因为它只是一个简单的脚本。

谢谢

3 个答案:

答案 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.
}