小巧、快速、可靠。
请选择其中三项。
事务

1. 事务控制语法

begin-stmt

BEGIN EXCLUSIVE TRANSACTION DEFERRED IMMEDIATE

commit-stmt

COMMIT TRANSACTION END

rollback-stmt

ROLLBACK TRANSACTION TO SAVEPOINT savepoint-name

2. 事务

除了在事务中,不会发生任何读或写操作。任何访问数据库的命令(基本上是任何 SQL 命令,除了少数 PRAGMA 语句)都会在没有事务的情况下自动启动事务。自动启动的事务将在最后一个 SQL 语句完成时提交。

可以使用 BEGIN 命令手动启动事务。此类事务通常会持续到下一个 COMMIT 或 ROLLBACK 命令。但是,如果数据库关闭,或者发生错误并且指定了 ROLLBACK 冲突解决算法,事务也会回滚。有关 ROLLBACK 冲突解决算法的更多信息,请参阅 ON CONFLICT 子句的文档。

END TRANSACTION 是 COMMIT 的别名。

使用 BEGIN...COMMIT 创建的事务不会嵌套。对于嵌套事务,请使用 SAVEPOINTRELEASE 命令。上面的语法图中显示的 ROLLBACK 命令的“TO SAVEPOINT name”子句仅适用于 SAVEPOINT 事务。无论事务是由 SAVEPOINT 还是先前的 BEGIN 启动的,尝试在事务中调用 BEGIN 命令都会导致错误。COMMIT 命令和没有 TO 子句的 ROLLBACK 命令在 SAVEPOINT 事务上与它们在 BEGIN 启动的事务上的工作方式相同。

2.1. 读事务与写事务

SQLite 支持来自不同数据库连接的多个并发读事务(可能在不同的线程或进程中),但只有一个并发写事务。

读事务仅用于读取。写事务允许读写。读事务由 SELECT 语句启动,写事务由诸如 CREATE、DELETE、DROP、INSERT 或 UPDATE 之类的语句启动(统称为“写语句”)。如果在读事务活动时发生写语句,则读事务将尽可能升级为写事务。如果其他数据库连接已经修改了数据库或正在修改数据库,则无法升级为写事务,并且写语句将使用 SQLITE_BUSY 失败。

在读事务活动时,由其他数据库连接实现的任何数据库更改都不会被启动读事务的数据库连接看到。如果数据库连接 X 正在保持读事务,则其他数据库连接 Y 可能在 X 的事务仍然打开时更改数据库内容,但是 X 无法看到这些更改,直到事务结束。在读事务活动时,X 将继续看到数据库在 Y 实现更改之前的历史快照。

2.2. DEFERRED、IMMEDIATE 和 EXCLUSIVE 事务

事务可以是 DEFERRED、IMMEDIATE 或 EXCLUSIVE。默认事务行为是 DEFERRED。

DEFERRED 意味着事务实际上直到第一次访问数据库时才会启动。在内部,BEGIN DEFERRED 语句只是在数据库连接上设置一个标志,该标志关闭通常在最后一个语句完成时发生的自动提交。这会导致自动启动的事务一直持续到显式 COMMIT 或 ROLLBACK,或者直到错误或 ON CONFLICT ROLLBACK 子句引发回滚。如果 BEGIN DEFERRED 后的第一个语句是 SELECT,则会启动读事务。随后的写语句将尽可能将事务升级为写事务,或者返回 SQLITE_BUSY。如果 BEGIN DEFERRED 后的第一个语句是写语句,则会启动写事务。

IMMEDIATE 使数据库连接立即启动一个新的写操作,无需等待写语句。如果另一个数据库连接上已存在活动写事务,BEGIN IMMEDIATE 可能会使用 SQLITE_BUSY 失败。

EXCLUSIVE 与 IMMEDIATE 类似,因为它会立即启动写事务。EXCLUSIVE 和 IMMEDIATE 在 WAL 模式 中相同,但在其他日志记录模式中,EXCLUSIVE 会阻止其他数据库连接在事务进行时读取数据库。

2.3. 隐式事务与显式事务

隐式事务(自动启动的事务,而不是由 BEGIN 启动的事务)在最后一个活动语句完成时自动提交。语句在最后一个游标关闭时完成,这在准备好的语句被 重置完成 时会得到保证。一些语句可能在重置或完成之前出于事务控制的目的而“完成”,但不能保证这一点。确保语句已“完成”的唯一方法是在该语句上调用 sqlite3_reset()sqlite3_finalize()。用于增量 BLOB I/O 的打开的 sqlite3_blob 也算作未完成的语句。 sqlite3_blob关闭 时完成。

显式 COMMIT 命令立即运行,即使有待处理的 SELECT 语句。但是,如果存在待处理的写操作,COMMIT 命令将使用错误代码 SQLITE_BUSY 失败。

如果另一个线程或进程有打开的读连接,尝试执行 COMMIT 也可能导致 SQLITE_BUSY 返回代码。当 COMMIT 以这种方式失败时,事务将保持活动状态,COMMIT 可以稍后在读取器有机会清除后重试。

在非常旧版本的 SQLite(早于 3.7.11 版本 - 2012-03-20)中,如果存在任何待处理的查询,ROLLBACK 将使用错误代码 SQLITE_BUSY 失败。在更新版本的 SQLite 中,ROLLBACK 将继续进行,待处理的语句通常会被中止,导致它们返回 SQLITE_ABORTSQLITE_ABORT_ROLLBACK 错误。在 SQLite 版本 3.8.8(2015-01-16)及更高版本中,只要 ROLLBACK 不修改数据库模式,待处理的读取将在 ROLLBACK 之后继续运行。

如果 PRAGMA journal_mode 设置为 OFF(从而禁用回滚日志文件),则 ROLLBACK 命令的行为未定义。

3. 对事务中错误的响应

如果在事务中发生某些类型的错误,事务可能会或可能不会自动回滚。可能导致自动回滚的错误包括

对于所有这些错误,SQLite 都会尝试撤消它正在处理的语句,并将同一事务中先前语句的更改保持完整,并继续事务。但是,根据正在评估的语句以及发生错误的位置,SQLite 可能需要回滚并取消整个事务。应用程序可以使用 sqlite3_get_autocommit() C 语言接口来确定 SQLite 采取了哪种行动。

建议应用程序通过显式发出 ROLLBACK 命令来响应上述错误。如果事务已经由错误响应自动回滚,则 ROLLBACK 命令将使用错误失败,但这不会造成任何损害。

未来版本的 SQLite 可能会扩展可能导致自动事务回滚的错误列表。未来版本的 SQLite 可能会更改错误响应。特别是,我们可能会选择在未来版本的 SQLite 中简化接口,从而导致上述错误强制执行无条件回滚。

本页面上次修改时间:2023-03-14 14:31:07 UTC