SQL:事务控制语言

SQL:事务控制语言

事务是关系型数据库保护数据的完整性和可靠性的基础部分。事务被用于所有 DDL 和 DML 命令。

ACID 事务

事务用于将一系列底层的改变组合成单个的,逻辑上的更新。事务可以是简单地更新某个值,也可以是复杂的多步过程,比如将几个不同的行插入到多个表中。

当事务被打开或启动,随着单独的数据操作命令被发起,它们变成事务的一部分。当逻辑过程完成时,事务被提交,以应用所有的改变到永久的数据库记录上。如果因为某些原因提交失败,事务被回滚,移除所有修改的痕迹。事务能被手动回滚。

可靠,稳定的事务标准是一个 ACID 测试。ACID 表示 AtomicConsistentIsolated,和 Durable。任何值得使用的事务系统必须具备这些品质:

  • Atomic:事务应该是原子的,从某种意义上说改变不能被分割成更小的块。当事务被提交给数据库时,要么整个事务被应用,要么整个事务没有被应用。仅应用事务的部分是不可能的。
  • Consistent:事务应当保持数据库的一致性。通常数据库有一些规则和限制,帮助保证存储的数据是正确的,并且和数据库的设计保持一致。假设数据库以一个一致的状态启动,应用事务必须保证数据库的一致性。这很重要,因为数据库在事务被打开时,被允许不一致 (通常也需要这样做)。例如,当传输基金时,在从某一账户减去和对另一账户添加之间的某一时刻,数据库中所表示的基金的总数被改变了,可能和所记录的总数不一致。这是可以接受的,只要事务在提交时能保持一致性。
  • Isolated:一个打开的事务必须与其他客户端隔离。当一个客户端打开一个事务,并开始发起单个改变命令,这些命令的结果对于该客户端是可见的。然而,这些改变对于其他访问该数据库的系统应该是不可见的,在提交整个事务之间,也不应该将它们集成到永久的数据库记录中。反过来说,在事务开始后其他客户端提交的改变不应该对该事务可见。事务需要隔离来保证原子性和一致性。如果其他客户端能看到半应用的事务,事务本质上就不能称为是原子的了,也不能保持数据库的一致性了。
  • Durable:事务必须是持久的。如果事务被成功提交,它必须成为数据库永久且不可逆转的一部分。一旦成功状态返回,即使进程被杀死,系统断电或者数据库文件系统消失,一旦重启,提交的改变应该存在于数据库中。反过来说,如果在事务被提交前系统断电,在重启时事务所做出的改变不应该出现在数据库中。

大部分人认为事务的原子性属性是最重要的属性,但是这 4 个方面必须一起合作以保证数据库的完整性。特别是持久性常常被忽视。SQLite 保证事务被成功提交后,改变被物理的写入到永久存储中。相较于传统的文件操作,通常写入到操作系统文件缓冲中。更新可能在缓冲中保存几秒钟到几分钟,然后才被写入到存储中。即使这样,数据也有可能在设备缓冲中等待最终被写入到物理存储中。虽然缓冲能增加效率,但这也意味着应用确实不知道它的数据何时被安全的提交到永久存储中。

事务不仅仅用于写数据。如果你需要使用多次查询收集数据,为一个拓展的只读操作打开一个事务有时十分有用。打开一个事务保证你对数据库的视角的一致性,保证数据在两次查询间不会改变。例如,你使用一次查询来收集一批记录 ID,然后对每个 ID 值发起一系列查询。将所有的查询包含到一个事务中保证了所有的查询看到相同的数据集。

SQL 事务

通常,SQLite 处于自动提交 (autocommit) 模式。这意味着 SQLite 自动为每个命令启动一个事务,处理命令 (假设没有产生错误),自动提交事务。

自动提交模式可以通过显式打开一个事务来禁用。BEGIN 命令被用于启动或打开一个事务。一旦一个显式事务被打开,它将保持打开状态直到它被提交或回滚。关键词 TRANSACTION 是可选的:

BEGIN [ DEFERRED | IMMEDIATE | EXCLUSIVE ] [TRANSACTION]

SQLite 指定的可选关键词 DEFERREDIMMEDIATEEXCLUSIVE 控制需要的读写锁如何被获取。如果一次只有一个客户端访问数据库,锁定模式在很大程度上是无关紧要的。当超过一个客户端同时访问数据库时,锁定模式定义了如何在保证事务成功的前提下平衡每个访问。

默认情况下,所有事务 (包含自动提交的事务) 使用 DEFERRED 模式。在这一模式下,在数据库锁被需要前不会获取任何数据库锁。这是最“睦邻”的模式了,允许其他客户端继续访问和使用数据库,直到事务别无选择只能进行加锁。这种模式允许其他客户端继续使用数据库,但是如果在事务需要锁时锁不可用,事务将会失败且可能会回滚并重新启动。

BEGIN IMMEDIATE 尝试立刻获取保留的锁。如果成功,它保证在写锁被需要时它们对事务可用,但也允许其他客户端的只读操作继续访问数据库。EXCLUSIVE 模式尝试锁定以排除所有的客户端,包括只读的客户端。虽然 IMMEDIATEEXCLUSIVE 对其他客户端更加严格,它们的好处是如果所需的锁不可用,它们将立即失败,而不是在发起 DDL 或 DML 命令之后。

一旦事务打开,你可以继续发起其他的 SQL 命令,包括 DDL 和 DML 命令。COMMIT 命令被用于关闭一个事务并向数据库提交改变。你也可以使用别名 END。和 BEGIN 一样,关键词 TRANSACTION 是可选的。

COMMIT [TRANSACTION]
END [TRANSACTION]

一旦 COMMIT 成功返回,所有改变将被完全提交到数据库中,且对其他客户端可见。

事务可以手动回滚,以取消事务和它所包含的改变。如果有错误发生,回滚一组改变则十分有用。错误可能是一个数据库错误,例如在插入记录时磁盘空间被耗尽,或者是一个应用的逻辑错误,例如向一个不存在的订单分配一个发票。在这种情况下,继续事务毫无意义,数据库也不能保存不一致的数据。最好的方式就是回滚并再次尝试。

尝试取消一个事务并回滚所有做出的改变,你可与以使用 ROLLBACK 命令。

ROLLBACK [TRANSACTION]

ROLLBACK 将撤销并恢复所有当前事务做出的改变,并关闭该事务。

COMMITROLLBACK 都会终止当前事务,使 SQLite 返回自动提交模式。

保存点

除了遵循 ACID 的事务外,SQLite 还支持 save-points。保存点允许你在事务中标记特定的点。随后你可以接受或回滚到某个保存点,不必提交或回滚整个事务。你可以同时设置多个活动的保存点。保存点有时被称为 nested transactions

保存点通常和大的,多步的事务一起使用,其中一些步骤或者子过程需要回滚的能力。保存点允许事务在某一时刻回滚一步。它还允许应用尝试不同的分支,如果某一分支失败,可以尝试另一分支,无序回滚整个事务。某种意义上,保存点可以被认为是 SQL 命令流中的“撤销”标记。

你可以使用 SAVEPOINT 命令创建保存点。因为可以定义多个保存点,你必须提供一个名字以标识保存点:

SAVEPOINT savepoint_name

保存点的行为如同栈。当你创建一个新的保存点,他被压入栈顶。保存点的标识不需要唯一,如果多次使用相同的保存点标识符,距栈顶最近的那个被使用。

为了释放保存点并接受所有自设置保存点起已做出的改变,使用 RELEASE 命令:

RELEASE [SAVEPOINT] savepoint_name

RELEASE 命令不向硬盘提交任何改变。相反,它将保存点堆栈中所有的改变平摊到命名保存点之下的层中。保存点随后被移除。任何被命名保存点包含的保存点被自动释放。

取消一组命令,撤销所有自保存点被设置之后的改变,使用 ROLLBACK TO 命令:

ROLLBACK [TRANSACTION] TO [SAVEPOINT] savepoint_name

与事务 ROLLBACK 不同,保存点 ROLLBACK 不关闭和消除保存点。ROLLBACK TO 回滚并取消任何自保存点被建立起发起的改变,但是保持事务状态与在发起 SAVEPOINT 之后的事务状态完全相同。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值