关于python:SQLAlchemy和SQLite:数据库被锁定

SQLAlchemy and SQLite: database is locked

我有一个使用最新sqlalchemy的python脚本。
当我使用sqlite,仅sqlite,其他数据库工作正常时,出现以下错误:

1
sqlalchemy.exc.OperationalError: (OperationalError) database is locked u'SELECT blabla....

有什么提示吗?

从我的代码示例(简化)中,我有几种类似的方法可以选择,更新和删除内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class MyDb(object):
    def __init__(self):
        engine = create_engine("sqlite:///file", poolclass=NullPool, pool_threadlocal=True)
        engine.pool_size=1
        engine.pool_timeout = 60
        self.sess = sessionmaker(bind=engine)

    def del_stuff(self):
        sess = self.sess()
        sess.query(Stuff).delete()
        try:
            sess.commit()
        except:
            sess.rollback()

    def set_stuff(self, id, bar):
        sess = self.sess()
        sess.query(Foo).get(id).bar = bar
        try:
            sess.commit()
        except:
            sess.rollback()

对数据库进行写操作(例如发送UPDATE,INSERT或DELETE)时,SQLite会锁定数据库。使用ORM时,这些信息将按刷新发送。数据库将保持锁定状态,直到出现COMMIT或ROLLBACK为止。

在多线程情况下,我通常会看到"数据库已锁定"错误。一个线程将锁定数据库,而另一个线程将尝试对其进行写入。如果第一个线程在超时时间(如果我记得的话,默认为4-5秒)内没有释放锁,则第二个线程会引发OperationalError。

知道何时进行刷新可能很棘手,因此,如果会话具有autoflush=True(默认设置),则会对数据库进行写操作,因为任何查询都会引起刷新。有时打开SQL日志记录可以帮助您确定何时发生:

1
logging.getLogger('sqlalchemy.engine').setLevel(logging.INFO)

这里有一些相关文档:http://docs.sqlalchemy.org/en/rel_0_9/dialects/sqlite.html#database-locking-behavior-concurrency


sqlite数据库一次只允许一个进程访问它。也许您有一个使用数据库的单独过程?


您应该对线程中的所有对象使用单个会话。 sqlite确实不喜欢多个连接,而sqlalchemy实际上是每个会话的连接(看起来您可能为每个类都有一个会话,这意味着在一个线程中有多个会话)。


通过任何开发人员工具检查数据库中所有未决的提交。

正如上面每个人都说过的,sqlite数据库一次只允许一个进程访问它。就我而言,我将数据库浏览器用于sqlite,同样,我没有提交查询。这也锁定了数据库,并且不允许应用程序写入数据库。


就我而言,逻辑很简单,没有多线程,问题的根源似乎很平庸。

'SQLite is not designed for a high level of write concurrency. The
database itself, being a file, is locked completely during write
operations within transactions, meaning exactly one"connection" (in
reality a file handle) has exclusive access to the database during
this period - all other"connections" will be blocked during this
time.'

……从而启发了一个主意:断开数据库浏览器的连接,该浏览器是我在工作期间用来检查数据库的。
而且效果很好。
因此,如果可能的话,请检查是否未通过其他工具连接到sqlite;)


检查您的代码是否有以下几点:

  • 对于所有应用程序生命周期,MyDb实例必须为一个。 MyDb必须是单身人士。
  • 尝试对引擎使用"普通"策略,但不要对pool_threadlocal=True使用
  • 每个逻辑请求的关闭会话均已完成。
  • 例如:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    def set_stuff(self, id, bar):
        sess = self.sess()
        sess.query(Foo).get(id).bar = bar
        try:
            sess.commit()
        except:
            sess.rollback()
        finally:
            sess.close()


    只需使用StaticPool。并遵循以下答案(scoped_session):https://stackoverflow.com/a/9621251

    create_engine(DB_PATH, echo=False, poolclass=StaticPool, connect_args={'check_same_thread': False})


    也遇到了同样的问题:

    1
    2
    3
    4
    5
    6
      File"/usr/local/lib/python2.7/dist-packages/sqlalchemy/engine/default.py", line 590, in do_execute
        cursor.execute(statement, parameters)
    sqlalchemy.exc.OperationalError: (sqlite3.OperationalError) database is locked
    [SQL: DELETE FROM vminds4 WHERE vminds4.id = ?]
    [parameters: (2,)]
    (Background on this error at: http://sqlalche.me/e/e3q8)

    最后,到达这里,因为我只是打开了另一个终端,打开了sqlite3文件,所以在关闭窗口后,它就可以了!


    我的答案仅适用于那些正在使用flask数据库并且准备删除其数据库以删除数据库锁的用户。如果您正在尝试,那么可以肯定地可以通过运行python脚本再次将数据添加到表中。

    开始了....

  • 删除烧瓶项目中存在的data.sqlite文件

  • 删除Flask项目中存在的migrations文件夹

  • 现在运行以下命令来创建新数据库:

    • flask db init
    • flask db migration -m"表"
    • flask DB升级
  • 现在,您可以运行python脚本将数据添加到数据库中,也可以
    使用python promt / flask shell手动将数据添加到表中。