【发布时间】:2021-11-22 05:17:43
【问题描述】:
我正在开发一个 PyQt 应用程序,它使用 QTableView 和 QSqlTableModel 显示来自 SQLite 数据库的数据。主视图设计为只读。用户可以启动编辑器来编辑数据库中的值。编辑器使用sqlite3 在数据库中进行更改。 (由于 Qt 在 C++ 和 Python 之间的类型转换很尴尬,我不想在编辑器中使用 Qt 数据库 API)。
我的问题:尝试在编辑器中更改数据库时,我收到sqlite3.OperationalError: database is locked。我设法弄清楚这是由于QTableView 由于其延迟获取特性而在数据库上持有锁(它只获取 256 行,然后在数据库连接上留下锁)。更多信息请访问this link。
我想出了以下解决方案:
- 在启动编辑器之前关闭 Qt 数据库连接 - 不理想,因为它会阻止主窗口在编辑器打开时工作
- 在启动编辑器之前清除
QSqlTableModel实例 - 与上述相同的问题 - 在启动编辑器之前使用
QSqlTableModel.fetchMore()获取所有数据-这似乎释放了锁定,但如果主窗口仍然可以操作,我想锁定可以随时重新建立,防止进一步写入? - 通过子类化
QSqlTableModel或QAbstractItemModel创建一个新类并自己控制锁定
在我选择最后一个之前,有没有更简单的选择?
【问题讨论】:
-
“尴尬的类型转换”到底是什么意思,我相信您可以使用
QItemDelegate覆盖它们。 -
@mugiseyebrows 我发现如果您的数据库中有 NULL,PyQt 会将它们作为空字符串返回,并且您无法再将它们与数据库中的实际空字符串区分开来。这是因为 C++
QtVariant类型被“智能”地自动转换为 Python 类型。这可以解决,但这足以阻止我使用 PyQt 数据库 API。 (另外,使用sqlite3会产生更好的代码)。 -
使用两个连接而不是一个连接并重写
QSqlTable中已有的内容(更新和缓存),这反过来又会造成复杂性,对我来说似乎不是很好的代码。 -
SQLite 是一个很棒的工具,既快速又轻量。但它不能很好地支持对同一个数据库的多次访问。恕我直言,您在这里有一个主要的一般设计问题。它可以通过使用更重的数据库引擎(如 PostgreSQL 或 MariaDB)来解决,或者让编辑器不直接访问数据库,或者......但是让多个进程访问同一个 SQLite 数据库可能会成为维护噩梦的根源...... .
-
@JussiNurminen NULL 值的问题可以很容易地解决,这在 PyQt 文档中进行了解释:Support for QVariant。简而言之,您可以像这样抑制自动转换:
sip.enableautoconversion(QVariant, False); ... # do stuff that returns variant values ...; sip.enableautoconversion(QVariant, True)。这将暂时将值作为包装的 QVariant 而不是 python 类型返回,因此您可以使用value.isNull()等。