在使用DBeaver操作SQLite时,提交事务没有效果

后端开发 2026-07-09

我在使用 SQLiteDBeaver。最近我接到一个大学作业,要求展示数据库的 锁定机制。于是我决定用DBeaver来做。

我可以用 MySQL 解决得很好,但一旦使用 SQLite,问题就会非常严重。

因为我要展示 锁定机制,我使用了两种不同的 SQL scripts/windows 来更好地理解它。然后我在 Window/SQL Script1: 里运行了以下代码

START TRANSACTION;
SELECT * FROM Account WHERE account_id = 1 FOR UPDATE;
UPDATE Account SET balance = balance - 2000 WHERE account_id = 1;
COMMIT;

然后我在 Windows/SQL Script2: 里运行了以下代码

UPDATE Account SET balance = balance + 1000 WHERE account_id = 1;

如何运行这段代码:

  1. 运行START部分
  2. 运行FOR UPDATE部分
  3. 运行UPDATE部分
  4. 运行第二个窗口的UPDATE部分(它给了我 Executing query.........
  5. 从窗口1 提交

用MySQL这样做时,效果正常,得到的结果也正确。

但每次在使用 SQLite,搭配下列代码

BEGIN IMMEDIATE;

UPDATE Accounts
SET balance = balance - 2000
WHERE account_id = 1;

COMMIT;

时,它会给出各种类型的错误,

SQL Error [1]: [SQLITE_ERROR] SQL error or missing database (cannot start a transaction within a transaction)

有时会出现如下这类错误:

SQL Error [1]: [SQLITE_ERROR] SQL error or missing database (cannot start a transaction within a transaction)

有谁能帮我找出在 SQLITE 中如何解决吗?

解决方案

我在Alma Linux 9.8上使用SQLite 3.34。

我无法解释DBeaver的行为,但我建议先用命令行测试场景,以确保实际使用了哪些语句。

如果我尝试用两个BEGIN IMMEDIATE语句来运行该场景:

在会话1 得到

sqlite> begin immediate;
sqlite> update account set balance = balance + 1000 where account_id = 1;
sqlite>

在会话2 得到

sqlite> begin immediate;
Error: database is locked
sqlite>

如果我尝试用BEGIN语句来运行场景:

在会话1 得到

sqlite> begin;
sqlite> update account set balance = balance + 1000 where account_id = 1;
sqlite>

在会话2 得到

sqlite> begin;
sqlite> update account set balance = balance + 1000 where account_id = 1;
Error: database is locked
sqlite>

这是预期之中的,因为SQLite的锁定是在数据库级别进行的,而不是按行级别进行的,具体请参见

https://sqlite.org/lockingv3.html

我不建议用SQLite来测试数据库锁定,因为 https://sqlite.org/whentouse.html 的说法是

If many threads and/or processes need to write the database at the same instant (and they cannot queue up and take turns) then it is best to select a database engine that supports that capability, which always means a client/server database engine.

SQLite only supports one writer at a time per database file. But in most cases, a write transaction only takes milliseconds and so multiple writers can simply take turns. SQLite will handle more write concurrency than many people suspect. Nevertheless, client/server database systems, because they have a long-running server process at hand to coordinate access, can usually handle far more write concurrency than SQLite ever will.

MySQL或 PostgreSQL被设计为多用户数据库,像所有客户端-服务器数据库引擎一样:在测试数据库锁定时,应使用客户端-服务器数据库。

站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章