15

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

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

12 回答 12

27

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

于 2015-02-26T16:36:28.630 回答
5

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

于 2012-12-15T19:07:44.627 回答
5

Check any commits pending in database through any developer tools.

As everyone told above sqlite databases only allow one process to access it at a time. In my case, I am using DB browser for sqlite and in the same, I didn't commit a query. That's also lock the DB and will not allow the application to write to database.

于 2019-04-04T02:44:40.903 回答
4

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

于 2013-02-05T22:39:15.837 回答
4
于 2019-07-24T22:15:05.993 回答
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()
于 2012-12-18T10:17:18.137 回答
2

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

db.session.close_all()

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

于 2021-07-21T09:34:00.330 回答
2

也遇到了同样的问题:

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

于 2020-05-11T09:09:51.430 回答
0

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

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

于 2020-07-25T13:10:27.127 回答
0

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

于 2021-11-19T14:40:44.257 回答
-1

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

开始了....

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

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

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

    • 烧瓶数据库初始化
    • 烧瓶数据库迁移-m“表”
    • 烧瓶数据库升级
  4. 现在您可以运行 python 脚本将数据添加到数据库中,也可以使用 python promt/flask shell 手动将数据添加到表中。

于 2019-11-22T11:07:55.837 回答
-3

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

于 2020-11-26T09:44:45.070 回答