订阅专栏
如果您有一个只读数据库,则不必担心事务。但是对于你将要构建的几乎所有应用程序,情况并非如此。因此,交易的概念和管理对于您的应用程序的成功至关重要。
事务是Oracle数据库作为一个单元处理的一个或多个SQL语句的序列:要么执行所有语句,要么都不执行。事务隐含地从获取TX锁的任何操作开始:
发出修改数据的语句(例如,插入,更新,删除,合并)
发出SELECT ... FOR UPDATE语句时
使用SET TRANSACTION语句或DBMS_TRANSACTION包显式启动事务时
发出COMMIT或ROLLBACK语句会明确结束当前事务。
本文将介绍如何使用以下语句和功能定义,管理和控制应用程序中的事务:
提交和回滚
保存点
自治交易
SET TRANSACTION语句
您可以在下面的事务处理和控制(doc)以及Oracle Live SQL和Oracle Dev Gym资源的链接中找到更多详细信息。
提交和回滚
回想一下事务的定义:“事务是Oracle数据库作为一个单元处理的一个或多个SQL语句的序列:要么执行所有语句,要么都不执行。” 当所有语句都“执行”时,这意味着您已将它们提交或保存到数据库中。
使用COMMIT语句保存所有更改,并使其对其他用户可见。请记住:在提交之前,没有人能够看到特定会话中所做的更改。提交后,每个有权访问受影响表的用户现在都可以看到表的新“状态”。
使用ROLLBACK语句撤消自上次提交以来(或自您在会话中启动第一个事务以来)的所有更改。
此LiveSQL教程(Oracle Dev Gym上的开发人员数据库课程的一部分)演示了事务管理的这些基本元素。
可是等等!如果您只想撤消会话中的某些更改,但保留其他更改,准备在将来的某个时间点提交,该怎么办?欢迎来到保存点世界。
保存点
保存点允许您回滚部分事务而不是整个事务。每个会话的活动保存点数量不受限制。
回滚到保存点时,标记在该保存点之后的任何保存点都将被删除。回滚的保存点不会被删除。简单的回滚或提交会擦除所有保存点。
保存点名称是未声明的标识符。在事务中重用保存点名称会将保存点从其旧位置移动到事务中的当前点,这意味着回滚到保存点仅影响事务的当前部分。
对于我们之间的递归程序员:如果在递归子程序中标记保存点,则SAVEPOINT语句的新实例在递归下降的每个级别运行,但是您只能回滚到最近标记的保存点。
以下是使用保存点的示例(从同一个LiveSQL教程中提取):
CREATE TABLE玩具
(
toy_id INTEGER,
toy_name VARCHAR2(100),
颜色 VARCHAR2(10)
)
/
宣布
l_count INTEGER ;
开始
INSERT INTO玩具(toy_id,toy_name,颜色)
价值观(8,'Pink Rabbit','粉红色');
SAVEPOINT after_six;
INSERT INTO玩具(toy_id,toy_name,颜色)
价值观(9,'紫色忍者','紫色');
SELECT COUNT(*)
INTO l_count
来自玩具
WHERE toy_id IN(8,9);
DBMS_OUTPUT.put_line(l_count);
ROLLBACK TO SAVEPOINT after_six;
SELECT COUNT(*)
INTO l_count
来自玩具
WHERE toy_id IN(8,9);
DBMS_OUTPUT.put_line(l_count);
ROLLBACK ;
SELECT COUNT(*)
INTO l_count
来自玩具
WHERE toy_id IN(8,9);
DBMS_OUTPUT.put_line(l_count);
结束 ;
/
2
1
0
自治交易
默认情况下,执行COMMIT语句时,会保存会话中所有未保存的更改。当您回滚时,所有未保存的更改都将被删除。
但有时候,我们只想保存其中一个更改,而不保存其他更改。此方案的最典型用例是错误日志记录。我想将信息写入我的错误日志表并保存,但后来我需要回滚事务(毕竟,有一个错误)。
我可以使用保存点来执行此操作(请参阅上一节),但是当您调用可重用的日志记录程序时,很难一致且可靠。幸运的是,我可以简单地使我的错误记录过程成为一个自治事务。然后,我可以插入错误信息并提交该插入,而不会影响业务事务,随后将回滚该业务事务。
它很容易做到!
只需将此语句添加到过程或函数的声明部分......
PRAGMA AUTONOMOUS_TRANSACTION;
然后适用以下规则:
在关闭子程序并将控制权传递回调用块之前,必须提交或回滚在该子程序中进行的任何DML更改。
如果有任何未保存的更改,PL / SQL引擎将引发ORA-06519异常,如下所示:
创建 或 替换 功能没有返回 INTEGER
IS
PRAGMA AUTONOMOUS_TRANSACTION;
开始
UPDATE员工SET last_name = 'abc' ;
返回 1 ;
结束 ;
/
开始
DBMS_OUTPUT.put_line(无);
结束 ;
/
ORA- 06519:检测到并回滚了活动自治事务
ORA- 06512:在 “STEVEN.NOTHING”,第10行
ORA- 06512:在线路2
以下是在错误记录过程中使用此功能的示例:
CREATE OR REPLACE PACKAGE BODY error_mgr
IS
PROCEDURE log_error(app_info_in IN VARCHAR2)
IS
PRAGMA AUTONOMOUS_TRANSACTION;
c_code CONSTANT INTEGER:= SQLCODE ;
开始
INSERT INTO error_log(created_on,
由...制作,
错误代码,
调用堆栈,
errorstack,
回溯,
ERROR_INFO)
价值观(SYSTIMESTAMP,
用户,
c_code,
DBMS_UTILITY.format_call_stack,
DBMS_UTILITY.format_error_stack,
DBMS_UTILITY.format_error_backtrace,
app_info_in);
COMMIT ;
结束 ;
结束 ;
此LiveSQL脚本包含完整(和非常基本)的错误记录包。
此LiveSQL脚本演示了自治事务编译指示的效果。
SET TRANSACTION语句
使用SET TRANSACTION语句将当前事务建立为只读或读/写,建立其隔离级别,将其分配给指定的回滚段,或为事务指定名称。
当您将事务设置为只读时,查询将返回事务开始时存在的数据,并且 您只能运行select语句。以下是使用此选项的示例,该选项来自Chris Saxon出色的LiveSQL模块:
集交易阅读 只 ;
从玩具中选择 * ;
更新玩具
设定 价格=价格+ 1 ;
宣布
pragma autonomous_transaction;
开始
更新玩具套装价格= 99.00 ;
提交 ;
结束 ;
/
从玩具中选择 * ;
提交 ;
从玩具中选择 * ;
以下是在LiveSQL中运行时的结果:
Oracle仅支持两个隔离级别:Read Committed和Serializable。
阅读已提交
这是Oracle数据库的默认模式。使用read committed,您具有语句级一致性。这意味着每个DML命令(选择,插入,更新或删除)都可以在开始之前查看保存的所有数据。其他会话启动后保存的任何更改都将被隐藏。
它使用多版本并发控制(MVCC)来实现。更新或删除行时,会将行的当前状态存储在undo中。因此,其他事务可以使用此撤消来查看过去存在的数据。
序列化
将事务设置为可序列化时,数据库就像您是数据库的唯一用户一样。其他交易所做的更改对您隐藏。Serializable还会阻止您更改由此错误导致的其他事务修改的行:
ORA-08177 can't serialize access for this transaction
换句话说,你是孤立的。
当事务多次访问相同的行时,请考虑使用serializable,并且您将有许多人同时运行事务。