我创建了一个非常基本的脚本,定期将一些数据写入数据库:
测试.py
import sqlite3
import sys
import time
DB_CREATE_TABLE = 'CREATE TABLE IF NOT EXISTS items (item TEXT)'
DB_INSERT = 'INSERT INTO items VALUES (?)'
FILENAME = 'test.db'
def main():
index = int()
c = sqlite3.connect(FILENAME)
c.execute(DB_CREATE_TABLE)
c.commit()
while True:
item = '{name}_{index}'.format(name=sys.argv[1], index=index)
c.execute(DB_INSERT, (item,))
c.commit()
time.sleep(1)
index += 1
c.close()
if __name__ == '__main__':
main()
现在我可以通过多次运行脚本来实现简单的并发:
python3 test.py foo &
python3 test.py bar &
我试着读了一些关于脚本同时写入同一个数据库文件的文章,但是我仍然不确定我的脚本将如何处理这样的事件,我也不知道如何测试它。你知道吗
我的期望是,在不太可能的情况下,当我的脚本的两个实例试图在同一毫秒内写入数据库时,后一个实例将只是静静地等待,直到前一个实例完成它的工作。你知道吗
我当前的实现是否符合我的期望?如果没有,在发生此类事件时,它的行为如何?我如何修复它?你知道吗
TL;博士
这个脚本将符合预期。你知道吗
解释
当两个脚本实例试图同时写入的不太可能的事件发生时,第一个脚本实例将锁定数据库,第二个脚本实例将静默地等待一段时间,直到第一个脚本实例完成其事务,以便再次解锁数据库以供写入。你知道吗
更准确地说,第二个脚本实例等待5秒(默认情况下),然后用消息
database is locked
引发OperationalError
。正如@roganjosh所评论的,这种行为实际上是Python SQLite包装器特有的。文档states:测试
为了演示这两个实例的冲突事件,我修改了
main
函数:文档说明在提交事务之前,数据库一直处于锁定状态。因此,在事务期间简单地休眠应该足以测试它。你知道吗
测试1
我们运行以下命令:
第一个实例正在运行,1s后第二个实例正在运行。第一个实例创建一个10秒长的事务,第二个实例尝试写入数据库,等待,然后引发异常。日志显示:
测试2
我们运行以下命令:
第一个实例正在运行,1s后第二个实例正在运行。第一个实例创建一个3s长的事务,第二个实例尝试写入数据库并等待。因为它是在1s之后创建的,所以它必须等待3s-1s=2s,这比默认的5s小,这样两个事务都将成功完成。日志显示:
结论
事务完成所需的时间比锁定时间限制(5s)要小得多(毫秒),因此在这种情况下,脚本确实符合预期。但作为哈雷。注释:事务在队列中等待提交,因此对于大量使用或非常大的数据库,这不是一个好的解决方案,因为与数据库的通信将变得缓慢。你知道吗
相关问题 更多 >
编程相关推荐