Oracle官方文档翻译《Database Concepts 26ai》第13章-事务

13 Transactions(13 事务)

本章定义了事务并描述了数据库如何处理事务。

  • 事务简介
    事务是包含一个或多个 SQL 语句的逻辑原子工作单元。
  • 事务控制概述
    事务控制是对 DML 语句所做更改的管理,以及将 DML 语句分组为事务。
  • 隔离事务概述
    隔离事务是指在数据库恢复期间被隔离且不被恢复的事务。在释放锁之前,需要 DBA 的干预来解决问题。
  • 事务卫士概述
    事务卫士是一个 API,应用程序可以使用它来提供事务幂等性,即数据库能够保留一个保证的提交结果,表明事务是否已提交并完成。Oracle AI 数据库为 JDBC thin、OCI、OCCI 和 ODP.Net 提供此 API。
  • 应用程序连续性概述
    应用程序连续性尝试通过对计划内和计划外中断后不完整的应用程序请求进行重放,来对应用程序屏蔽中断。在此上下文中,一个请求是来自应用程序的一个工作单元。
  • 自治事务概述
    自治事务是可由另一个事务(主事务)调用的独立事务。你可以挂起调用事务,在自治事务中执行 SQL 操作并提交或撤销它们,然后恢复调用事务。
  • 分布式事务概述
    分布式事务是这样一种事务,它包含一个或多个语句,这些语句使用称为数据库链接的模式对象,更新分布式数据库中两个或多个不同节点上的数据。

Introduction to Transactions(事务简介)

事务是包含一个或多个 SQL 语句的逻辑原子工作单元。

事务将 SQL 语句分组,以便它们要么全部提交(意味着它们被应用到数据库),要么全部回滚(意味着它们从数据库中被撤销)。Oracle AI 数据库为每个事务分配一个称为事务 ID 的唯一标识符。

所有 Oracle 事务都遵守数据库事务的基本属性,即 ACID 属性。ACID 是以下特性的缩写:

  • 原子性
    事务的所有任务要么全部执行,要么一个都不执行。不存在部分事务。例如,如果一个事务开始更新 100 行,但在 20 次更新后系统发生故障,那么数据库将回滚对这 20 行的更改。
  • 一致性
    事务将数据库从一个一致状态带到另一个一致状态。例如,在一笔从储蓄账户扣款并贷记支票账户的银行交易中,故障绝不能导致数据库只贷记一个账户,这会导致数据不一致。
  • 隔离性
    事务的效果在事务提交之前对其他事务不可见。例如,一位更新 hr.employees 表的用户看不到其他用户同时对 employees 表所做的未提交更改。因此,对用户而言,事务看起来像是串行执行的。
  • 持久性
    已提交事务所做的更改是永久的。事务完成后,数据库通过其恢复机制确保事务的更改不会丢失。

事务的使用是数据库管理系统区别于文件系统的最重要方式之一。

  • 事务示例:账户借记和贷记
    为了说明事务的概念,请考虑一个银行数据库。
  • 事务的结构
    数据库事务由一个或多个语句组成。
  • 语句级原子性
    Oracle AI 数据库支持语句级原子性,这意味着 SQL 语句是原子工作单元,要么完全成功,要么完全失败。
  • 系统更改号 (SCN)
    系统更改号 (SCN) 是 Oracle AI 数据库使用的逻辑内部时间戳。

Sample Transaction: Account Debit and Credit(事务示例:账户借记和贷记)

为了说明事务的概念,请考虑一个银行数据库。

当客户将资金从储蓄账户转移到支票账户时,该事务必须包含三个独立的操作:

  • 减少储蓄账户余额
  • 增加支票账户余额
  • 在交易日记账中记录该交易

Oracle AI 数据库必须考虑两种情况。如果所有三个 SQL 语句都能保持账户余额正确,那么事务的效果可以应用到数据库。但是,如果出现诸如资金不足、无效账户号码或硬件故障等问题,导致事务中的一个或两个语句无法完成,那么数据库必须回滚整个事务,以确保所有账户的余额都正确。

下图说明了一个银行事务。第一条语句从储蓄账户 3209 中减去 500。第二条语句向支票账户 3208 中增加 500。第三条语句将转账记录插入日记账表。最后一条语句提交事务。

Figure 13-1 A Banking Transaction(图 13-1 银行事务)

Structure of a Transaction(事务的结构)

数据库事务由一个或多个语句组成。

具体而言,事务包含以下其中之一:

  • 一个或多个共同构成对数据库原子更改的数据操作语言 (DML) 语句
  • 一个数据定义语言 (DDL) 语句

事务有一个开始和一个结束。

  • 事务的开始
    当事务遇到第一个可执行的 SQL 语句时开始。
  • 事务的结束
    事务可以在不同情况下结束。

另请参见

  • "SQL 语句概述"
  • 《Oracle AI 数据库 SQL 语言参考》:了解 SQL 语句的类型
Beginning of a Transaction(事务的开始)

当事务遇到第一个可执行的 SQL 语句时开始。

可执行 SQL 语句是生成对数据库实例调用的 SQL 语句,包括 DML 和 DDL 语句以及 SET TRANSACTION 语句。

当事务开始时,Oracle AI 数据库将该事务分配到一个可用的撤销数据段,以记录新事务的撤销条目。事务 ID 直到分配了撤销段和事务表槽时才会分配,这发生在第一个 DML 语句期间。事务 ID 对于事务是唯一的,它表示撤销段号、槽和序列号。

以下示例执行 UPDATE 语句以开始一个事务,并查询 V$TRANSACTION 以获取事务的详细信息:

sql 复制代码
SQL> UPDATE hr.employees SET salary=salary; 
107 rows updated.
 
SQL> SELECT XID AS "txn id", XIDUSN AS "undo seg", XIDSLOT AS "slot", 
  2  XIDSQN AS "seq", STATUS AS "txn status"
  3  FROM V$TRANSACTION;
 
txn id             undo seg       slot        seq txn status
---------------- ---------- ---------- ---------- ----------------
0600060037000000          6          6         55 ACTIVE

另请参见

"撤销段"

End of a Transaction(事务的结束)

事务可以在不同情况下结束。

当发生以下任一操作时,事务结束:

  • 用户发出不包含 SAVEPOINT 子句的 COMMITROLLBACK 语句。
    在提交中,用户显式或隐式地请求使事务中的更改永久生效。事务所做的更改只有在事务提交后才是永久的并对其他用户可见。
  • 用户运行 DDL 命令,如 CREATEDROPRENAMEALTER
    数据库在每个 DDL 语句之前和之后隐式地发出 COMMIT 语句。如果当前事务包含 DML 语句,那么 Oracle AI 数据库首先提交该事务,然后将 DDL 语句作为一个新的单语句事务运行并提交。
  • 用户正常退出大多数 Oracle AI 数据库实用程序和工具,导致当前事务被隐式提交。用户断开连接时的提交行为取决于应用程序且可配置。

注意

应用程序应始终在程序终止前显式提交或撤销事务。

  • 客户端进程异常终止,导致事务使用存储在事务表和撤销段中的元数据被隐式回滚。

一个事务结束后,下一个可执行的 SQL 语句自动启动下一个事务。以下示例执行 UPDATE 启动一个事务,用 ROLLBACK 语句结束该事务,然后执行 UPDATE 启动一个新事务(注意事务 ID 是不同的):

sql 复制代码
SQL> UPDATE hr.employees SET salary=salary; 
107 rows updated.
 
SQL> SELECT XID, STATUS FROM V$TRANSACTION;
 
XID              STATUS
---------------- ----------------
0800090033000000 ACTIVE
 
SQL> ROLLBACK;
 
Rollback complete.
 
SQL> SELECT XID FROM V$TRANSACTION;
 
no rows selected
 
SQL> UPDATE hr.employees SET last_name=last_name;
 
107 rows updated.
 
SQL> SELECT XID, STATUS FROM V$TRANSACTION;
 
XID              STATUS
---------------- ----------------
0900050033000000 ACTIVE

另请参见

  • "事务示例:账户借记和贷记":了解以提交结束的事务示例。
  • 《Oracle AI 数据库 SQL 语言参考》:了解 COMMIT

Statement-Level Atomicity(语句级原子性)

Oracle AI 数据库支持语句级原子性,这意味着 SQL 语句是原子工作单元,要么完全成功,要么完全失败。

成功的语句与已提交的事务不同。如果数据库将单个 SQL 语句作为原子单元解析并运行且没有错误,则该语句执行成功,例如在多行更新中所有行都被更改的情况。

如果 SQL 语句在执行期间导致错误,则该语句不成功,因此该语句的所有效果都被回滚。此操作是语句级回滚。此操作具有以下特征:

  • 不成功的 SQL 语句只会导致其自身本应执行的工作丢失。
    不成功的语句不会导致当前事务中在它之前的任何工作丢失。例如,如果"事务示例:账户借记和贷记"中第二个 UPDATE 语句的执行导致错误并被回滚,那么第一个 UPDATE 语句执行的工作不会被回滚。第一个 UPDATE 语句可以由用户显式提交或回滚。
  • 回滚的效果如同该语句从未运行过一样。
    原子语句的任何副作用,例如执行该语句时触发的触发器,都被视为原子语句的一部分。作为原子语句一部分生成的所有工作要么全部成功,要么全部不成功。

导致语句级回滚的错误的一个例子是尝试插入重复的主键。涉及死锁(对相同数据的竞争)的单个 SQL 语句也可能导致语句级回滚。然而,在 SQL 语句解析期间发现的错误(如语法错误)尚未运行,因此不会导致语句级回滚。

另请参见

  • "SQL 解析"
  • "锁和死锁"
  • "触发器概述"

System Change Numbers (SCNs)(系统更改号 (SCN))

系统更改号 (SCN) 是 Oracle AI 数据库使用的逻辑内部时间戳。

SCN 对数据库内发生的事件进行排序,这对于满足事务的 ACID 属性是必需的。Oracle AI 数据库使用 SCN 来标记一个 SCN,在此 SCN 之前的所有更改已知已写入磁盘,以便恢复避免应用不必要的重做。数据库还使用 SCN 来标记对于一组数据不再存在重做的点,以便恢复可以停止。

SCN 以单调递增的序列出现。Oracle AI 数据库可以像时钟一样使用 SCN,因为观察到的 SCN 指示逻辑时间点,并且重复观察会返回相等或更大的值。如果一个事件的 SCN 低于另一个事件,那么它在数据库中的发生时间更早。多个事件可能共享相同的 SCN,这意味着它们在数据库中的发生时间相同。

每个事务都有一个 SCN。例如,如果事务更新一行,那么数据库记录此更新发生时的 SCN。此事务中的其他修改具有相同的 SCN。当事务提交时,数据库为此提交记录一个 SCN。

Oracle AI 数据库在系统全局区 (SGA) 中递增 SCN。当事务修改数据时,数据库将一个新的 SCN 写入分配给该事务的撤销数据段。然后,日志写入进程立即将该事务的提交记录写入在线重做日志。提交记录具有该事务的唯一 SCN。

Oracle AI 数据库还使用 SCN 作为其实例恢复和介质恢复机制的一部分。

另请参见

"实例恢复概述"

Overview of Transaction Control(事务控制概述)

事务控制是对 DML 语句所做更改的管理,以及将 DML 语句分组为事务。

通常,应用程序设计者关心事务控制,以便以逻辑单元完成工作并保持数据一致性。

事务控制涉及使用以下语句,如"事务控制语句"中所述:

  • COMMIT 语句结束当前事务,并使事务中执行的所有更改永久生效。COMMIT 还会清除事务中的所有保存点并释放事务锁。
  • ROLLBACK 语句反转当前事务中所做的工作;它导致自上次 COMMITROLLBACK 以来的所有数据更改被丢弃。ROLLBACK TO SAVEPOINT 语句撤销自上次保存点以来的更改,但不会结束整个事务。
  • SAVEPOINT 语句在事务中标识一个点,稍后你可以回滚到该点。

表 13-1 中的会话说明了事务控制的基本概念。

Table 13-1 Transaction Control(表 13-1 事务控制)

T 会话 说明
t0 COMMIT; 此语句结束会话中任何现有事务。
t1 SET TRANSACTION NAME 'sal_update'; 此语句开始一个事务并将其命名为 sal_update
t2 UPDATE employees SET salary = 7000 WHERE last_name = 'Banda'; 此语句将 Banda 的薪水更新为 7000。
t3 SAVEPOINT after_banda_sal; 此语句创建一个名为 after_banda_sal 的保存点,使此事务中的更改能够回滚到此点。
t4 UPDATE employees SET salary = 12000 WHERE last_name = 'Greene'; 此语句将 Greene 的薪水更新为 12000。
t5 SAVEPOINT after_greene_sal; 此语句创建一个名为 after_greene_sal 的保存点,使此事务中的更改能够回滚到此点。
t6 ROLLBACK TO SAVEPOINT after_banda_sal; 此语句将事务回滚到 t3,撤销 t4 时对 Greene 薪水的更新。sal_update 事务尚未结束。
t7 UPDATE employees SET salary = 11000 WHERE last_name = 'Greene'; 此语句在事务 sal_update 中将 Greene 的薪水更新为 11000。
t8 ROLLBACK; 此语句回滚事务 sal_update 中的所有更改,结束事务。
t9 SET TRANSACTION NAME 'sal_update2'; 此语句在会话中开始一个新事务并将其命名为 sal_update2
t10 UPDATE employees SET salary = 7050 WHERE last_name = 'Banda'; 此语句将 Banda 的薪水更新为 7050。
t11 UPDATE employees SET salary = 10950 WHERE last_name = 'Greene'; 此语句将 Greene 的薪水更新为 10950。
t12 COMMIT; 此语句提交事务 sal_update2 中所做的所有更改,结束事务。该提交确保更改保存在在线重做日志文件中。
  • 事务名称
    事务名称是一个可选的、用户指定的标签,用于提醒事务正在执行的工作。你可以使用 SET TRANSACTION ... NAME 语句命名事务,如果使用,它必须是事务的第一条语句。
  • 活动事务
    活动事务是指已经开始但尚未提交或回滚的事务。
  • 保存点
    保存点是事务上下文中用户声明的中间标记。
  • 事务回滚
    对未提交事务的回滚会撤销该事务中 SQL 语句已执行的任何数据更改。
  • 事务提交
    提交结束当前事务,并使事务中执行的所有更改永久生效。

另请参见

《Oracle AI 数据库 SQL 语言参考》:了解事务控制语句

Transaction Names(事务名称)

事务名称是一个可选的、用户指定的标签,用于提醒事务正在执行的工作。你可以使用 SET TRANSACTION ... NAME 语句命名事务,如果使用,它必须是事务的第一条语句。

在表 13-1 中,第一个事务被命名为 sal_update,第二个被命名为 sal_update2

事务名称提供以下优势:

  • 更容易监控长时间运行的事务并解决疑问的分布式事务。
  • 你可以在应用程序中查看事务名称以及事务 ID。例如,数据库管理员在监控系统活动时,可以在 Oracle 企业管理器(Enterprise Manager)中查看事务名称。
  • 数据库将事务名称写入事务审计重做记录,因此你可以使用 LogMiner 在重做日志中搜索特定事务。
  • 你可以使用事务名称在数据字典视图(如 V$TRANSACTION)中查找特定事务。

另请参见

  • 《Oracle AI 数据库参考》:了解 V$TRANSACTION
  • 《Oracle AI 数据库 SQL 语言参考》:了解 SET TRANSACTION

Active Transactions(活动事务)

活动事务是指已经开始但尚未提交或回滚的事务。

在表 13-1 中,sal_update 事务中第一个修改数据的语句是对 Banda 薪水的更新。从成功执行此更新到 ROLLBACK 语句结束事务,sal_update 事务都是活动的。

事务所做的数据更改是临时的,直到事务提交或回滚。在事务结束前,数据的状态如下表所示。

Table 13-2 State of the Data Before the Transaction Ends(表 13-2 事务结束前数据的状态)

状态 说明 了解更多
Oracle AI 数据库在 SGA 中生成了撤销信息。 撤销数据包含事务的 SQL 语句所更改的旧数据值。 "读已提交隔离级别的读一致性"
Oracle AI 数据库在 SGA 的在线重做日志缓冲区中生成了重做信息。 重做日志记录包含对数据块的更改和对撤销块的更改。 "重做日志缓冲区"
已对 SGA 的数据库缓冲区进行了更改。 对于已提交事务的数据更改,存储在 SGA 的数据库缓冲区中,不一定会由数据库写入器 (DBW) 立即写入数据文件。磁盘写入可以发生在提交之前或之后。 "数据库缓冲区高速缓存"
受数据更改影响的行被锁定。 其他用户无法更改受影响行中的数据,也无法看到未提交的更改。 "锁定行为总结"

Savepoints(保存点)

保存点是事务上下文中用户声明的中间标记。

在内部,保存点标记解析为一个 SCN。保存点将长事务分成较小的部分。

如果在长事务中使用保存点,则可以选择稍后回滚在事务中当前点之前但在事务中声明的保存点之后所执行的工作。因此,如果出现错误,则无需重新提交每条语句。

表 13-1 创建了保存点 after_banda_sal,以便对 Greene 薪水的更新可以回滚到此保存点。

  • 回滚到保存点
    在未提交事务中回滚到保存点意味着撤销在指定保存点之后所做的任何更改,但这并不意味着回滚事务本身。
  • 排队的事务
    根据场景,在回滚到保存点后,等待先前锁定资源的事务可能仍被阻塞。
Rollback to Savepoint(回滚到保存点)

在未提交事务中回滚到保存点意味着撤销在指定保存点之后所做的任何更改,但这并不意味着回滚事务本身。

当事务回滚到保存点时,如表 13-1 中运行 ROLLBACK TO SAVEPOINT after_banda_sal 时,会发生以下情况:

  1. Oracle AI 数据库仅回滚在保存点之后运行的语句。
    在表 13-1 中,ROLLBACK TO SAVEPOINT 导致对 Greene 的 UPDATE 被回滚,但不会回滚对 Banda 的 UPDATE
  2. Oracle AI 数据库保留在 ROLLBACK TO SAVEPOINT 语句中指定的保存点,但所有后续保存点都会丢失。
    在表 13-1 中,ROLLBACK TO SAVEPOINT 导致 after_greene_sal 保存点丢失。
  3. Oracle AI 数据库释放指定保存点之后获取的所有表锁和行锁,但保留在保存点之前获取的所有数据锁。
    事务保持活动状态并可以继续。

另请参见

  • 《Oracle AI 数据库 SQL 语言参考》:了解 ROLLBACKSAVEPOINT 语句
  • 《Oracle AI 数据库 PL/SQL 语言参考》:了解事务处理和控制
Enqueued Transactions(排队的事务)

根据场景,在回滚到保存点后,等待先前锁定资源的事务可能仍被阻塞。

当一个事务被另一个事务阻塞时,它会在阻塞事务本身上排队,因此整个阻塞事务必须提交或回滚,被阻塞的事务才能继续。

在下表所示的场景中,会话 1 回滚到执行 DML 语句之前创建的保存点。但是,会话 2 仍被阻塞,因为它在等待会话 1 的事务完成。

Table 13-3 Rollback to Savepoint Example(表 13-3 回滚到保存点示例)

T 会话 1 会话 2 会话 3 说明
t0 UPDATE employees SET salary=7000 WHERE last_name= 'Banda'; 会话 1 开始一个事务。该会话在 Banda 行上放置排他锁 (TX),在表上放置子排他表锁 (SX)。
t1 SAVEPOINT after_banda_sal; 会话 1 创建一个名为 after_banda_sal 的保存点。
t2 UPDATE employees SET salary=12000 WHERE last_name= 'Greene'; 会话 1 锁定 Greene 行。
t3 UPDATE employees SET salary=14000 WHERE last_name= 'Greene'; 会话 2 尝试更新 Greene 行,但未能获取锁,因为会话 1 持有此行的锁。会话 2 中没有开始任何事务。
t4 ROLLBACK TO SAVEPOINT after_banda_sal; 会话 1 回滚对 Greene 薪水的更新,这释放了 Greene 的行锁。在 t0 获取的表锁未被释放。此时,会话 2 仍被会话 1 阻塞,因为会话 2 在会话 1 的事务上排队,而该事务尚未完成。
t5 UPDATE employees SET salary=11000 WHERE last_name= 'Greene'; Greene 行当前已解锁,因此会话 3 获取锁以更新 Greene 行。此语句在会话 3 中开始一个事务。
t6 COMMIT; 会话 1 提交,结束其事务。现在,会话 2 对其 Greene 行更新的排队位于会话 3 中的事务之后。

另请参见

"锁持续时间":了解关于 Oracle AI 数据库何时释放锁的更多信息

Rollback of Transactions(事务回滚)

对未提交事务的回滚会撤销该事务中 SQL 语句已执行的任何数据更改。

事务回滚后,该事务中所做工作的效果不再存在。在回滚整个事务而不引用任何保存点时,Oracle AI 数据库执行以下操作:

  • 使用相应的撤销段撤销事务中所有 SQL 语句所做的所有更改
    每个活动事务的事务表条目都包含一个指向该事务所有撤销数据(按应用的反序)的指针。数据库从撤销段读取数据,反转操作,然后将撤销条目标记为已应用。因此,如果事务插入了一行,那么回滚会将其删除。如果事务更新了一行,那么回滚会反转该更新。如果事务删除了一行,那么回滚会重新插入它。在表 13-1 中,ROLLBACK 反转了对 Greene 和 Banda 薪水的更新。
  • 释放事务所持有的所有数据锁
  • 清除事务中的所有保存点
    在表 13-1 中,ROLLBACK 删除了保存点 after_banda_salafter_greene_sal 保存点已被 ROLLBACK TO SAVEPOINT 语句删除。
  • 结束事务
    在表 13-1 中,ROLLBACK 使数据库处于与初始 COMMIT 执行后相同的状态。

回滚的持续时间取决于修改的数据量。

另请参见

  • "撤销段"
  • 《Oracle AI 数据库 SQL 语言参考》:了解 ROLLBACK 命令

Commits of Transactions(事务提交)

提交结束当前事务,并使事务中执行的所有更改永久生效。

在表 13-1 中,第二个事务以 sal_update2 开始,并以显式的 COMMIT 语句结束。两个 UPDATE 语句产生的更改现在变为永久。

当事务提交时,会发生以下操作:

  • 数据库为 COMMIT 生成一个 SCN。
    关联撤销表空间的内部事务表记录该事务已提交。事务对应的唯一 SCN 被分配并记录在事务表中。
  • 日志写入进程 (LGWR) 将重做日志缓冲区中剩余的重做日志条目写入在线重做日志,并将事务 SCN 写入在线重做日志。这个原子事件构成事务的提交。
  • Oracle AI 数据库释放行和表上持有的锁。
    正在排队等待未提交事务所持有锁的用户被允许继续其工作。
  • Oracle AI 数据库删除保存点。
    在表 13-1 中,sal_update 事务中不存在保存点,所以没有保存点被清除。
  • Oracle AI 数据库执行提交清理。
    如果包含已提交事务数据的修改块仍在 SGA 中,并且没有其他会话正在修改它们,那么数据库将从这些块中删除与锁相关的事务信息(ITL 条目)。
    理想情况下,COMMIT 会清理这些块,以便后续的 SELECT 不必执行此任务。如果对于特定行不存在 ITL 条目,则该行未被锁定。如果对于特定行存在 ITL 条目,则该行可能被锁定,因此会话必须检查撤销段头以确定此感兴趣的事务是否已提交。如果感兴趣的事务已提交,那么会话会清理该块,这会生成重做。但是,如果 COMMIT 之前已清理了 ITL,则检查和清理是不必要的。

注意

因为块清理会生成重做,所以查询可能会生成重做,从而可能导致块在下一次检查点期间被写入。

  • Oracle AI 数据库将事务标记为完成。

事务提交后,用户就可以看到更改。

通常,无论事务大小如何,提交都是一个快速操作。提交的速度不会随着事务中修改的数据大小而增加。提交中最耗时的部分是由 LGWR 执行的物理磁盘 I/O。然而,LGWR 花费的时间量减少了,因为它一直在后台增量地写入重做日志缓冲区的内容。

默认行为是 LGWR 将重做同步写入在线重做日志,并且事务在将缓冲的重做写入磁盘后才向用户返回提交。但是,为了降低事务提交延迟,应用程序开发人员可以指定异步写入重做,以便事务无需等待重写写入磁盘,并可以立即从 COMMIT 调用返回。

另请参见

  • "可串行化隔离级别"
  • "锁定机制"
  • "后台进程概述":获取有关 LGWR 的更多信息
  • 《Oracle AI 数据库 PL/SQL 包和类型参考》:获取有关异步提交的更多信息

Overview of Quarantined Transactions(隔离事务概述)

隔离事务是指在数据库恢复期间被隔离且不被恢复的事务。在释放锁之前,需要 DBA 的干预来解决问题。

Oracle AI 数据库利用重做和撤销来实现数据一致性。当数据库在崩溃后打开时,应用重做将数据库前滚以获取所有已提交的更改,这称为缓存恢复,而撤销则回滚由未提交且因崩溃而变为非活动的事务所做的更改。这称为崩溃恢复。数据库打开时不会等待对未提交事务的撤销被应用,以实现更快的启动。相反,它在事务表中将事务的状态标记为"非活动",然后快速打开数据库。然后,由系统监控 (SMON) 后台进程异步执行对非活动事务的撤销应用,这称为事务恢复。

SMON 恢复非活动事务的另一种情况是在实例恢复期间。Oracle RAC 实例可能在有活动运行的事务时崩溃。那些非活动事务持有的行锁会阻塞其余存活 RAC 实例上相同行上的事务。剩余实例之一上的 SMON 后台进程以两个阶段执行实例恢复:缓存恢复,随后是事务恢复。PMON 后台进程也可以将清理失败进程期间终止大型事务的工作转交给 SMON。

SMON 进程执行系统级任务,如清理未使用的临时段、合并连续的区以及许多其他任务。它是一个不可恢复的进程,意味着 SMON 中的崩溃会导致 CDB 实例崩溃。SMON 事务恢复失败可能由于多种原因发生:

  • 物理数据、索引或撤销块损坏
  • 逻辑数据损坏
  • 内存损坏

崩溃不仅会停止对 SMON 正在主动恢复的事务的恢复,还会停止对其他非活动事务的恢复。当存在持续性故障时,Oracle 支持建议客户禁用 SMON 事务恢复并打开数据库以减少影响。这会导致非活动事务持有的行锁持续更长时间。这会严重影响关键业务操作。

任何无法恢复的事务都会被隔离,并保持未恢复状态,直到 DBA 能够解决问题。DBA 会收到关于隔离事务的通知,并且必须立即采取行动,以便释放隔离事务持有的行锁。

DBA 会在各种日志和视图中收到关于隔离事务存在的警报,以帮助识别隔离事务及其被隔离的原因。DBA 使用这些信息来解决特定问题,以便可以解除隔离。

当故障跨越多个事务或涉及整个 PDB 时,例如由于代码错误导致的逻辑数据损坏、多个块的物理损坏或 PDB SGA 损坏,隔离失败的非活动事务恢复可能会也可能不会有所帮助。这取决于这些故障的根本原因是否相同,因为恢复其他非活动事务可能会遇到同样的问题。即使在隔离了一些事务之后,系统仍会在不一致的状态下继续运行。当故障是由于逻辑数据损坏导致时,这可能很危险,因为它会随着时间的推移而扩散。为了防止这种情况发生,事务隔离限制为三 (3),超过此限制后,隔离将升级到数据库级别,并且如果为 PDB 启用了归档日志记录并且可以关闭 PDB,则将使用 shutdown abort 终止 PDB。PDB 的事务恢复会自动禁用,以便 DBA 可以在下次启动时纠正问题。问题解决后,DBA 应该为下次启动启用恢复。

注意

由于 Oracle Data Guard 使用逻辑复制,因此在使用 Oracle Data Guard 时,隔离元数据不会复制到备用服务器。因此,备用服务器上的事务隔离视图(如 DBA_QUARANTINED_TRANSACTIONS)的内容可能与主服务器上的条目不同。

相关主题

  • 自动事务隔离

Overview of Transaction Guard(事务卫士概述)

事务卫士是一个 API,应用程序可以使用它来提供事务幂等性,即数据库能够保留一个保证的提交结果,表明事务是否已提交并完成。Oracle AI 数据库为 JDBC thin、OCI、OCCI 和 ODP.Net 提供此 API。

可恢复错误是由外部系统故障引起的,与正在执行的应用程序会话逻辑无关。可恢复错误发生在前台进程、网络、节点、存储和数据库的计划内和计划外中断之后。如果中断断开了客户端应用程序和数据库之间的连接,那么应用程序会收到断开连接的错误消息。连接断开时正在运行的事务称为进行中事务。

为了决定是重新提交事务还是将结果(已提交或未提交)返回给客户端,应用程序必须确定进行中事务的结果。在 Oracle 数据库 12c 之前,返回给客户端的提交消息不是持久的。检查事务并不能保证它在被检查后不会提交,这可能导致重复事务和其他形式的逻辑损坏。例如,用户在线购书时可能会刷新网页浏览器,从而为同一本书被收费两次。

  • 事务卫士的优势
    从 Oracle 数据库 12c 开始,事务卫士为应用程序提供了一种工具,用于在可恢复中断后确定进行中事务的状态。
  • 事务卫士的工作原理
    本节解释了丢失提交消息的问题,以及事务卫士如何使用逻辑事务 ID 来解决该问题。
  • 事务卫士:示例
    在此场景中,由于可恢复错误,提交消息丢失。

另请参见

  • "事务简介"
  • 《Oracle AI 数据库开发指南》:了解事务卫士
  • 《Oracle Real Application Clusters 管理和部署指南》:了解如何为事务卫士配置服务

Benefits of Transaction Guard(事务卫士的优势)

从 Oracle 数据库 12c 开始,事务卫士为应用程序提供了一种工具,用于在可恢复中断后确定进行中事务的状态。

使用事务卫士,应用程序可以确保事务执行不超过一次。例如,如果在线书店应用程序确定先前提交的提交失败,那么应用程序可以安全地重新提交。

事务卫士提供了一种至多一次执行的工具,以避免应用程序执行重复提交。事务卫士为每个事务提供一个已知的结果。

事务卫士是 Oracle AI 数据库的核心能力。应用程序连续性在对最终用户屏蔽中断时使用事务卫士。没有事务卫士,在错误后重试的应用程序可能会导致重复事务被提交。

另请参见

  • "应用程序连续性概述":了解应用程序连续性,它与事务卫士合作,帮助开发人员实现高应用程序可用性
  • 《Oracle AI 数据库开发指南》:了解事务卫士,包括受支持和包含的事务类型

How Transaction Guard Works(事务卫士的工作原理)

本节解释了丢失提交消息的问题,以及事务卫士如何使用逻辑事务 ID 来解决该问题。

  • 丢失的提交消息
    在设计幂等性时,开发人员必须解决在提交语句提交后发生通信故障的问题。提交消息不会持久保存在数据库中,因此在故障后无法检索。
  • 逻辑事务 ID
    Oracle AI 数据库通过使用称为逻辑事务 ID 的全局唯一标识符来解决通信故障。
Lost Commit Messages(丢失的提交消息)

在设计幂等性时,开发人员必须解决在提交语句提交后发生通信故障的问题。提交消息不会持久保存在数据库中,因此在故障后无法检索。

下图是客户端应用程序与数据库之间交互的高层表示。

Figure 13-2 Lost Commit Message(图 13-2 丢失的提交消息)

在标准提交情形中,数据库提交事务并向客户端返回成功消息。在图 13-2 中,客户端提交了一个提交语句,并收到一条消息,指出通信失败。这种类型的故障可能由于多种原因发生,包括数据库实例故障或网络中断。在此场景中,客户端不知道事务的状态。

在通信故障之后,数据库可能仍在运行提交,并且不知道客户端已断开连接。检查事务状态并不能保证活动事务在被检查后不会提交。如果客户端基于此过时信息重新发送提交,那么数据库可能会重复该事务,从而导致逻辑损坏。

Logical Transaction ID(逻辑事务 ID)

Oracle AI 数据库通过使用称为逻辑事务 ID 的全局唯一标识符来解决通信故障。

此 ID 包含会话首次连接时分配的逻辑会话号,以及一个运行提交号,该提交号在每次会话提交或回滚时更新¹。从应用程序的角度来看,逻辑事务 ID 唯一标识了在发生故障的会话上提交的最后一个数据库事务。

对于客户端中提交了一个或多个事务的每次往返,数据库存储一个逻辑事务 ID。对于提交数据的每次往返,此 ID 可以为应用程序与数据库之间的交互提供事务幂等性。

¹ 对于 Oracle Real Application Clusters (Oracle RAC),逻辑事务 ID 包括数据库实例号作为前缀。

至多一次协议通过要求数据库执行以下操作来启用对提交结果的访问:

  • 在约定的重试保留期内维护逻辑事务 ID
  • 在提交时持久保存逻辑事务 ID

当事务运行时,数据库和客户端都持有逻辑事务 ID。数据库在认证时、从连接池借用时,以及在客户端驱动程序的每次执行一个或多个提交操作的往返时,都会给客户端一个逻辑事务 ID。

在应用程序可以确定可恢复错误后最后一个事务的结果之前,应用程序使用 Java、OCI、OCCI 或 ODP.Net API 获取客户端持有的逻辑事务 ID。然后,应用程序调用 PL/SQL 过程 DBMS_APP_CONT.GET_LTXID_OUTCOME,并传入逻辑事务 ID,以确定最后一次提交的结果:已提交(truefalse)和用户调用已完成(truefalse)。

当使用事务卫士时,应用程序可以在错误可恢复且会话上的最后一个事务尚未提交时重放事务。当最后一个事务已提交且用户调用已完成时,应用程序可以继续。应用程序可以使用事务卫士将已知结果返回给客户端,以便客户端决定下一个要采取的操作。

另请参见

  • 《Oracle AI 数据库开发指南》:了解逻辑事务 ID
  • 《Oracle AI 数据库 PL/SQL 包和类型参考》:了解关于 DBMS_APP_CONT.GET_LTXID_OUTCOME 过程的更多信息

Transaction Guard: Example(事务卫士:示例)

在此场景中,由于可恢复错误,提交消息丢失。

事务卫士使用逻辑事务 ID 来保留 COMMIT 语句的结果,确保事务有一个已知的结果。

Figure 13-3 Check of Logical Transaction Status(图 13-3 逻辑事务状态检查)

在图 13-3 中,数据库通知应用程序事务是否已提交,以及最后一个用户调用是否已完成。然后,应用程序可以将结果返回给最终用户。可能性包括:

  • 如果事务已提交且用户调用已完成,那么应用程序可以将结果返回给最终用户并继续。
  • 如果事务已提交但用户调用未完成,那么应用程序可以将结果随警告一起返回给最终用户。示例包括丢失的输出绑定或丢失的处理行数。某些应用程序依赖于这些额外信息,而另一些则不。
  • 如果用户调用未提交,那么应用程序可以将此信息返回给最终用户,或安全地重新提交。该协议是有保证的。当提交状态返回 false 时,最后一次提交将被阻止提交。

另请参见

《Oracle AI 数据库开发指南》:了解如何使用事务卫士

Overview of Application Continuity(应用程序连续性概述)

应用程序连续性尝试通过对计划内和计划外中断后不完整的应用程序请求进行重放,来对应用程序屏蔽中断。在此上下文中,一个请求是来自应用程序的一个工作单元。

通常,一个请求对应于一个 Web 请求在单个数据库连接上的 DML 语句和其他数据库调用。通常,请求由从连接池检出和检入数据库连接之间所做的调用来界定。

本节包含以下主题:

  • 应用程序连续性的优势
  • 应用程序连续性架构

Benefits of Application Continuity(应用程序连续性的优势)

开发人员面临的一个基本问题是如何对最终用户屏蔽丢失的数据库会话。

应用程序连续性尝试通过在任何组件中断数据库与客户端之间的对话时恢复数据库会话来解决问题。恢复的数据库会话包括所有状态、游标、变量以及最新的一个事务(如果存在)。

  • 应用程序连续性的用例
    在典型情况下,客户端已向数据库提交了一个请求,该数据库已建立了事务性和非事务性状态。
  • 用于计划维护的应用程序连续性
    用于计划中断的应用程序连续性使应用程序能够为可以可靠排空或迁移的数据库会话继续操作。
Use Case for Application Continuity(应用程序连续性的用例)

在典型情况下,客户端已向数据库提交了一个请求,该数据库已建立了事务性和非事务性状态。

客户端的状态保持为当前状态,可能包含输入数据、返回数据以及缓存的数据和变量。然而,应用程序需要操作其内的数据库会话状态丢失了。

如果客户端请求已启动一个或多个事务,那么应用程序面临以下可能性:

  • 如果已发出提交,则返回给客户端的提交消息不是持久的。客户端不知道请求是否已提交,以及它在非事务性处理状态中达到了哪一步。
  • 如果未发出提交,或者发出了但未执行,则进行中事务被回滚,并且必须使用处于正确状态的会话重新提交。

如果重放成功,那么针对计划内和计划外中断的数据库用户服务不会中断。如果数据库检测到应用程序看到并可能已作用的数据发生了变化,则重放会被拒绝。当超过允许开始重放的时间、应用程序使用了受限调用,或者应用程序已使用 disableReplay 方法显式禁用了重放时,不会尝试重放。

另请参见

《Oracle Real Application Clusters 管理和部署指南》:了解关于应用程序连续性如何为数据库会话工作的更多信息

Application Continuity for Planned Maintenance(用于计划维护的应用程序连续性)

用于计划中断的应用程序连续性使应用程序能够为可以可靠排空或迁移的数据库会话继续操作。

计划的维护不必中断应用程序工作。应用程序连续性为活动工作提供了时间,使其可以从当前位置排空到当前不受维护影响的新位置。在排空间隔结束时,会话可能会留在计划进行维护的数据库实例上。应用程序连续性无需强制断开这些会话,而是可以将这些会话故障转移到剩余的站点,并重新提交任何进行中的事务。

启用应用程序连续性后,数据库可以执行以下操作:

  • 在维护期间,对于传入的或现有的工作均不报告错误
  • 将活动数据库会话重定向到其他功能性服务
  • 在维护期间和之后,根据需要重新平衡数据库会话

使用 SRVCTL 实用程序、全局数据服务控制实用程序 (GDSCTL) 和 Oracle Data Guard Broker 的 drain_timeoutstop_option 服务属性来控制计划维护期间的排空行为。DBMS_SERVICE 包提供了底层基础结构。

另请参见

  • 《Oracle Real Application Clusters 管理和部署指南》:了解有关应用程序连续性的更多信息
  • 《Oracle AI 数据库 PL/SQL 包和类型参考》:了解关于 DBMS_SERVICE 的更多信息
  • 《Oracle Real Application Clusters 管理和部署指南》:SRVCTL 命令参考
  • 《Oracle AI 数据库全局数据服务概念和管理指南》:GDSCTL 命令参考

Application Continuity Architecture(应用程序连续性架构)

应用程序连续性的关键组件是运行时、重新连接和重放。

各阶段如下:

  1. 正常运行时
    在此阶段,应用程序连续性执行以下任务:
    • 识别数据库请求
    • 确定本地和数据库调用是否可重放
    • 如有必要,构建代理对象以启用重放,并管理队列
    • 保留原始调用及对这些调用的验证,直到数据库请求结束或重放被禁用
  2. 重新连接
    此阶段由可恢复错误触发。应用程序连续性执行以下任务:
    • 确保已为数据库请求启用重放
    • 管理超时
    • 获取到数据库的新连接,然后验证这是否是有效的数据库目标
    • 使用事务卫士确定最后一个事务是否成功提交(已提交的事务不会被重新提交)
  3. 重放
    应用程序连续性执行以下任务:
    • 重放队列中保留的调用
    • 如果在重放期间结果出现用户可见的变化,则禁用重放
    • 不允许提交,但允许最后一次召回(遇到错误的那次)提交

成功重放后,请求从故障点继续。

另请参见

  • "事务卫士概述"
  • 《Oracle Real Application Clusters 管理和部署指南》:了解有关应用程序连续性的更多信息
  • 《Oracle AI 数据库 JDBC 开发者指南》:了解有关 JDBC 和应用程序连续性的更多信息

Overview of Autonomous Transactions(自治事务概述)

自治事务是可由另一个事务(主事务)调用的独立事务。你可以挂起调用事务,在自治事务中执行 SQL 操作并提交或撤销它们,然后恢复调用事务。

自治事务适用于必须独立执行的操作,无论调用事务是提交还是回滚。例如,在股票购买事务中,无论整个股票购买是否完成,你都希望提交客户数据。此外,即使整个事务回滚,你也希望将错误消息记录到调试表中。

自治事务具有以下特征:

  • 自治事务看不到主事务所做的未提交更改,也不与主事务共享锁或资源。
  • 自治事务中的更改在自治事务提交后对其他事务可见。因此,用户可以访问更新的信息,而无需等待主事务提交。
  • 自治事务可以启动其他自治事务。除资源限制外,对可以调用多少级别的自治事务没有限制。

在 PL/SQL 中,自治事务在自治范围内执行,自治范围是用编译指示 AUTONOMOUS_TRANSACTION 标记的例程。在此上下文中,例程包括顶层匿名 PL/SQL 块以及 PL/SQL 子程序和触发器。编译指示是指导编译器执行某个编译选项的指令。编译指示 AUTONOMOUS_TRANSACTION 指示数据库,此过程在执行时,将作为一个独立于其父事务的新自治事务来执行。

下图显示了控制如何从主例程 (MT) 流向自治例程,然后再返回。主例程是 proc1,自治例程是 proc2。自治例程可以在控制返回主例程之前提交多个事务(AT1 和 AT2)。

Figure 13-4 Transaction Control Flow(图 13-4 事务控制流程)

当你进入自治例程的可执行部分时,主例程挂起。当你退出自治例程时,主例程恢复。

在图 13-4 中,proc1 中的 COMMIT 不仅使其自己的工作永久化,而且使其会话中执行的任何未完成工作也永久化。然而,proc2 中的 COMMIT 仅使 proc2 事务中执行的工作永久化。因此,事务 AT1 和 AT2 中的 COMMIT 语句对 MT 事务没有影响。

另请参见

《Oracle AI 数据库开发指南》和《Oracle AI 数据库 PL/SQL 语言参考》:了解如何使用自治事务

Overview of Distributed Transactions(分布式事务概述)

分布式事务是这样一种事务,它包含一个或多个语句,这些语句使用称为数据库链接的模式对象,更新分布式数据库中两个或多个不同节点上的数据。

分布式数据库是分布式系统中的一组数据库,它们对应用程序而言可以显示为单一数据源。数据库链接描述了一个数据库实例如何登录到另一个数据库实例。

与本地数据库上的事务不同,分布式事务会更改多个数据库上的数据。因此,分布式事务处理更加复杂,因为数据库必须将事务中更改的提交或回滚作为一个原子单元进行协调。整个事务必须提交或回滚。Oracle AI 数据库必须通过网络协调事务控制并维护数据一致性,即使发生网络或系统故障也是如此。

  • 两阶段提交
    两阶段提交机制保证参与分布式事务的所有数据库要么全部提交,要么全部撤销事务中的语句。该机制还保护由完整性约束、远程过程调用和触发器执行的隐式 DML。
  • 疑问事务
    当两阶段提交被任何类型的系统或网络故障中断时,就会发生疑问的分布式事务。

另请参见

《Oracle AI 数据库管理员指南》:了解如何管理分布式事务

Two-Phase Commit(两阶段提交)

两阶段提交机制保证参与分布式事务的所有数据库要么全部提交,要么全部撤销事务中的语句。该机制还保护由完整性约束、远程过程调用和触发器执行的隐式 DML。

在多个数据库之间的两阶段提交中,一个数据库协调分布式事务。发起节点称为全局协调器。协调器询问其他数据库是否准备好提交。如果任何数据库回答否,那么整个事务将被回滚。如果所有数据库都投票赞成,那么协调器将广播一条消息,使提交在每个数据库上永久生效。

两阶段提交机制对发出分布式事务的用户是透明的。实际上,用户甚至不需要知道事务是分布式的。表示事务结束的 COMMIT 语句会自动触发两阶段提交机制。在数据库应用程序体内包含分布式事务不需要编码或复杂的语句语法。

另请参见

  • 《Oracle AI 数据库管理员指南》:了解两阶段提交机制
  • 《Oracle AI 数据库 SQL 语言参考》

In-Doubt Transactions(疑问事务)

当两阶段提交被任何类型的系统或网络故障中断时,就会发生疑问的分布式事务。

例如,两个数据库向协调数据库报告它们已准备好提交,但协调数据库实例在收到消息后立即发生故障。这两个已准备好提交的数据库现在被悬置,等待结果通知。

恢复器 (RECO) 后台进程自动解决疑问的分布式事务的结果。在故障修复且通信重新建立后,每个本地 Oracle 数据库的 RECO 进程会自动在所有涉及的节点上一致地提交或回滚任何疑问的分布式事务。

在长期故障的情况下,Oracle AI 数据库使每个本地管理员能够手动提交或撤销任何因故障而处于疑问状态的分布式事务。此选项使本地数据库管理员能够释放因长期故障而无期限持有的任何锁定资源。

如果必须将数据库恢复到过去的某个时间点,则数据库恢复设施使其他站点的数据库管理员能够将其数据库返回到较早的时间点。此操作确保全局数据库保持一致。

另请参见

  • "恢复器进程 (RECO)"
  • 《Oracle AI 数据库管理员指南》:了解如何管理疑问事务
相关推荐
j7~18 小时前
【MYSQL】基本查询(表的增删查改)--详解
数据库·mysql·select·create·聚合函数·update·groupby
爱喝水的鱼丶18 小时前
SAP-ABAP:变量、常量、结构与内表声明(10篇博客合集) 第八篇:复杂业务场景下的声明组合:结构嵌套内表、内表包含结构的实现方法
运维·数据库·学习·算法·sap·abap
这个DBA有点耶18 小时前
集中式 vs 分布式:2026数据库选型决策树
数据库·分布式·决策树
鸽芷咕18 小时前
KingbaseES系统视图与Hints调优:从诊断到性能优化的进阶之路
数据库·oracle·性能优化
Pocker_Spades_A18 小时前
没公网IP怎么远程连数据库?PostgreSQL + cpolar,在任何网络环境下都能连上
网络·数据库·tcp/ip
数据与后端架构提升之路18 小时前
RAG 实战指南:深入浅出向量数据库 Milvus
数据库·milvus
风间琉璃"""19 小时前
Reverse5
数据库
一只fish19 小时前
Oracle官方文档翻译《Database Concepts 26ai》第11章-服务器端编程
数据库·oracle
. . . . .19 小时前
mysql常用SQL
数据库·sql·mysql