【问题标题】:SQLAlchemy and SQLite: database is lockedSQLAlchemy 和 SQLite:数据库被锁定
【发布时间】:2012-12-03 10:16:45
【问题描述】:

我有一个使用最新 sqlalchemy 的 python 脚本。 当我使用 sqlite 时,只有 sqlite,其他 db 运行良好,我收到以下错误:

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

有什么提示吗?

我的代码示例(简化),我有几个这样的方法来选择、更新和删除东西:

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()

【问题讨论】:

  • 上次我使用 sqlite,也有同样的问题,所以我改用 sql 而不是 sqlite :) 问题永远不会出现

标签: python sqlite python-2.7 sqlalchemy


【解决方案1】:

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

【讨论】:

    【解决方案2】:

    检查您的代码以了解以下几点:

    1. MyDb 的实例在所有应用程序生命周期中必须是一个。 MyDb 必须是单例。
    2. 尝试对引擎使用“普通”策略,但不要使用pool_threadlocal=True
    3. 每个逻辑请求的关闭会话都已完成。

    例如:

    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()
    

    【讨论】:

      【解决方案3】:

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

      【讨论】:

        【解决方案4】:

        当对数据库进行写入时,SQLite 会锁定数据库,例如发送 UPDATE、INSERT 或 DELETE 时。使用 ORM 时,这些会在刷新时发送。数据库将保持锁定状态,直到出现 COMMIT 或 ROLLBACK。

        我经常在多线程情况下看到“数据库被锁定”错误。一个线程将锁定数据库,另一个线程将尝试自己的写入。如果第一个线程没有在超时期限内释放锁(默认情况下为 4-5 秒,如果我记得的话),则会在第二个线程上引发 OperationalError。

        知道何时刷新可能很棘手,因此当会话具有autoflush=True(默认设置)时会写入数据库,因为任何查询都会导致刷新。有时打开 SQL 日志记录可以帮助澄清事情发生的时间:

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

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

        【讨论】:

          【解决方案5】:

          通过任何开发者工具检查数据库中任何待处理的提交。

          正如上面所说的,sqlite 数据库一次只允许一个进程访问它。就我而言,我使用的是 DB browser for sqlite,同样,我没有提交查询。这也锁定了数据库,不允许应用程序写入数据库。

          【讨论】:

            【解决方案6】:

            在我的情况下,逻辑很简单,没有多线程,问题的根源似乎很平庸......

            'SQLite 不是为高水平的写并发设计的。这 数据库本身,作为一个文件,在写入过程中被完全锁定 事务中的操作,意味着一个“连接”(在 现实一个文件句柄)具有对数据库的独占访问权限 在此期间 - 所有其他“连接”将在此期间被阻止 时间。'

            ...这样“启发”了一个想法:断开我在工作期间用来检查数据库的数据库浏览器。 而且效果很好。 因此,如果这可能是您的情况 - 检查您是否没有通过其他工具连接到您的 sqlite ;)

            【讨论】:

              【解决方案7】:

              我的答案只适用于那些正在尝试使用烧瓶数据库并且他们准备删除他们的数据库以移除数据库锁的人。如果您正在试验,那么您当然可以通过运行 python 脚本再次将数据添加到表中。

              我们来了....

              1. 删除烧瓶项目中的 data.sqlite 文件

              2. 删除烧瓶项目中的迁移文件夹

              3. 现在运行以下命令来创建一个新数据库:

                • 烧瓶数据库初始化
                • flask db migrate -m "tables"
                • 烧瓶数据库升级
              4. 现在您可以运行 python 脚本来将数据添加到数据库中,或者您可以 使用 python promt/flask shell 手动将数据添加到表中。

              【讨论】:

                【解决方案8】:

                也遇到了同样的问题:

                  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文件,然后关闭窗口后,它就可以工作了!

                【讨论】:

                  【解决方案9】:

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

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

                  【讨论】:

                    【解决方案10】:

                    如果表中有重复记录,可能会发生这种情况

                    【讨论】:

                      【解决方案11】:

                      我遇到了同样的错误,我可以通过以下方式修复:

                      db.session.close_all()
                      

                      对我来说,错误是由于打开的数据库连接过多,因为我使用的是 Spyder 控制台而不是终端

                      【讨论】:

                        【解决方案12】:

                        对于未来的参与者,在我的例子中,pandas to_sql 函数(使用 sqlalchemy 连接字符串)写入 CIFS 共享挂载上的 sqlite 文件失败了。相同的功能可以在 ext4 磁盘上运行。解决方法是将nobrl 添加到/etc/fstab 中的选项中,卸载,然后重新安装磁盘。然后to_sql 命令起作用了。

                        【讨论】:

                          猜你喜欢
                          • 1970-01-01
                          • 2011-10-30
                          • 1970-01-01
                          • 1970-01-01
                          • 2011-08-05
                          • 2015-05-11
                          • 2011-02-14
                          • 1970-01-01
                          • 1970-01-01
                          相关资源
                          最近更新 更多