几个星期前,我在SO上发布了关于如何在python中锁定sqlite3数据库的问题:
How to lock a sqlite3 database in Python?
但是,我不太相信答案是有效的。或者,也许我只是误解了答案。
以下是我遇到的情况:
然后我有一个像这样的函数:
def checkout(title, user):
con = get_connection_from_db()
with con:
checked_out_by = get_checked_out_by(title)
if checked_out_by == '': # If NOT checked out:
checkout(title, user)
print user, "checked out", title
elif checked_out_by == 'user':
print user, "already got it"
else:
print user, "can't check it out because", checked_out_by, "has it!"
因此checkout()函数首先验证书籍是否未签出,如果是,则签出书籍。请注意,我正在使用推荐的“with con:”技巧来确保所有内容都是事务性的,快乐的和copacetic。
但是,我运行了一堆并发测试并发现了问题。具体来说,当我同时运行以下两个调用时:
checkout('foo', 'steve')
checkout('foo', 'tim')
输出表明它不能正常工作。我希望看到以下两个可能的输出中的一个:
steve checked out foo
tim can't check it out because steve has it!
OR:
tim checked out foo
steve can't check it out because tim has it!
但偶尔,我会得到这个输出:
tim checked out foo
steve checked out foo
我认为'with con:'技巧将确保我的数据库调用将捆绑在一起。有人可以向我解释我是否/如何弄错了?如果是这样,有没有办法使这项工作?
答案 0 :(得分:30)
要获得特定时期的独占访问权限(不仅仅是在进行单个查询/交易时),您需要这样做;
con = sqlite3.connect()
con.isolation_level = 'EXCLUSIVE'
con.execute('BEGIN EXCLUSIVE')
#exclusive access starts here. Nothing else can r/w the db, do your magic here.
con.commit()
con.close()
希望这可以节省一些人,因为我刚刚完成了搜索/实验!
记住它不是独占的,直到你开始独占,它将保持独占,直到你关闭(或运行提交,我认为)。如果您不确定,可以随时使用python interpreter / CL sqlite3应用程序进行测试。
答案 1 :(得分:-1)
需要注意的一件重要事情是,当数据库被锁定时,这意味着它不接受多个编写器。但是,它确实接受了多个读者..
检查事务是否按预期工作的一种简单方法是将值写入数据库,然后在事务代码完成之前引发异常。如果没有写入值,则事务处理正常。否则,出了点问题。
数据库事务是一种乐观的并发方法,也就是说,它们只在它们即将提交时才会失败。既然看起来你正在寻找一种悲观的方法,也许你应该试试threading.Lock:
import threading
db_lock = threading.Lock()
def checkout(title, user):
with db_lock:
con = get_connection_from_db()
with con:
checked_out_by = get_checked_out_by(title)
if checked_out_by == '': # If NOT checked out:
checkout(title, user)
print user, "checked out", title
elif checked_out_by == 'user':
print user, "already got it"
else:
print user, "can't check it out because", checked_out_by, "has it!"