sqlite3.OperationalError: database is locked

2020年10月14日 / 12次阅读 / Last Modified 2020年10月22日
SQLite

python标准库自带sqlite3接口,在编译安装的时候,sqlite3也一起编译了。sqlite3是一个轻量自包含的文件数据库,没有独立的管理进程,因此,在基于此数据库编写系统的时候,并发访问就成了一个问题。

因为sqlite3是文件,一个进程在写入的时候,另一个进程就无法写入!而进程间的同步,需要我们自己处理。多线程也一样,python sqlite3模块默认不允许在线程间共享 connect 对象。

多线程序列化访问比较好处理,多进程可能就需要代码自己处理 database is locked 这个异常了!

sqlite3的事务类型

sqlite3的锁机制

下面这段测试代码,能够跑出 database is locked 异常,以此证明本文主题的存在:

$ cat test_sqlite3.py
import multiprocessing as mp
import sqlite3

def write():
    conn = sqlite3.connect('tdb')
    conn.isolation_level = None
    c = conn.cursor()

    for i in range(1000):
        c.execute("INSERT INTO mod2 VALUES (1,2,3)")


phlist = [mp.Process(target=write, args=(), daemon=True) for i in range(3)]

for ph in phlist:
    ph.start()

for ph in phlist:
    ph.join()

print('done')

运行时,有两个process会抛出异常:

$ python3 test_sqlite3.py
Process Process-2:
Traceback (most recent call last):
  File "/usr/local/python3.8.6/lib/python3.8/multiprocessing/process.py", line 315, in _bootstrap
    self.run()
  File "/usr/local/python3.8.6/lib/python3.8/multiprocessing/process.py", line 108, in run
    self._target(*self._args, **self._kwargs)
  File "test_sqlite3.py", line 16, in write
    c.execute("INSERT INTO mod2 VALUES (1,2,3)")
sqlite3.OperationalError: database is locked
Process Process-3:
Traceback (most recent call last):
  File "/usr/local/python3.8.6/lib/python3.8/multiprocessing/process.py", line 315, in _bootstrap
    self.run()
  File "/usr/local/python3.8.6/lib/python3.8/multiprocessing/process.py", line 108, in run
    self._target(*self._args, **self._kwargs)
  File "test_sqlite3.py", line 16, in write
    c.execute("INSERT INTO mod2 VALUES (1,2,3)")
sqlite3.OperationalError: database is locked

当看到此异常时,在sqlite3的shell中做select,也是一样的异常:

sqlite> select count(*) from mod2;
Error: database is locked
sqlite> select count(*) from mod2;
Error: database is locked

有一行代码很有趣:

conn.isolation_level = None

默认情况下,都需要调用commit函数才能真正写入数据库,而 isolation_level=None 后,对应的就是 sqlite3 的autocommit模式,也就不需要再调用commit函数了。

autocommit 顾名思义,就是每一次修改都有效,都默认支持了一次commit操作。因此 autocommit 模式下 insert 速度特别地慢!!一般别这样用。

-- EOF --

本文链接:https://www.pynote.net/archives/2570

留言区

《sqlite3.OperationalError: database is locked》有1条留言

电子邮件地址不会被公开。 必填项已用*标注

  • 麦新杰

    符合python DB-API2.0 (PEP 249)的sqlite3模块,其成员threadsafety显示:

    >>> import sqlite3
    >>> sqlite3.threadsafety
    1
    
    含义为:Threads may share the module, but not connections. [回复]


前一篇:
后一篇:

More


©Copyright 麦新杰 Since 2019 Python笔记

go to top