oracle事务嵌套研究

 
l        事务嵌套测试案例
(1)首先,建立一个表:
create table msg (msg varchar2(100));
(2)然后,建立子事务存储过程local。
create or replace procedure local is
cnt number := -1;   -- Global variables
   begin
      select count(*) into cnt from msg;
      dbms_output.put_line('local: # of rows is '||cnt);
       
      insert into msg values ('New Record');
      commit;
   end;
 
(3)最后,用如下PL/SQL匿名块调用local;
declare
   cnt number := -1;  
begin
      delete from msg ;
      commit;
      insert into msg values ('Row 1');
      local;
      select count(*) into cnt from msg;
      dbms_output.put_line('main: # of rows is '||cnt);
      rollback;
 
      local;
      insert into msg values ('Row 2');
      commit;
 
      local;
      select count(*) into cnt from msg;
      dbms_output.put_line('main: # of rows is '||cnt);
   end;
 
运行结果(注意打开set serveroutput on)如下:
local: # of rows is 1-> 子程序local中可以’看到’主匿名块中的uncommitted记录
main: # of rows is 2-> 主匿名块可以’看到’2条记录(它们都是被local commit掉的)
local: # of rows is 2-> 子程序local首先’看到’2条记录,然后又commit了第三条记录
local: # of rows is 4-> 子程序local又’看到’了新增加的记录(它们都是被local commit掉的),然后又commit了第五条记录
main: # of rows is 5-> 主匿名块最后看到了所有的记录.
 
PL/SQL 过程已成功完成。
 
(4)重建过程local,将commit改为rollback,如下:
create or replace procedure local is
cnt number := -1;   -- Global variables
   begin
      select count(*) into cnt from msg;
      dbms_output.put_line('local: # of rows is '||cnt);
       
      insert into msg values ('New Record');
      rollback;
   end;
 
执行第(3)步的PL/SQL匿名块,
运行结果(注意打开set serveroutput on)如下:
local: # of rows is 1
main: # of rows is 0-> 子程序把主匿名块的一条记录也rollback了,所以结果为0
local: # of rows is 0
local: # of rows is 1-> 主匿名块把自己的一条记录成功commt,子程序也可以看到
main: # of rows is 1
 
PL/SQL 过程已成功完成。
 
(5)重建过程local,将commit去掉,如下:
create or replace procedure local is
cnt number := -1;   -- Global variables
   begin
      select count(*) into cnt from msg;
      dbms_output.put_line('local: # of rows is '||cnt);
       
      insert into msg values ('New Record');
   end;
 
执行第(3)步的PL/SQL匿名块,
运行结果(注意打开set serveroutput on)如下:
local: # of rows is 1-> 子程序看到主匿名块uncommited的一条记录
main: # of rows is 2-> 主匿名块可以看到主匿名块和子程序插入的uncommited记录
local: # of rows is 0-> 主匿名块把主匿名块和子程序插入的记录全部rollback
local: # of rows is 2-> 主匿名块把主匿名块和子程序插入的记录全部commit
main: # of rows is 3
 
PL/SQL 过程已成功完成。
 
l        AUTONOMOUS TRANSACTION(自治事务)的介绍
AUTONOMOUS_TRANSACTION是指在function,procedure等subprograms中对事务进行自治管理,当在别的pl/sql block里去调用这些subprograms的时候这些subprograms并不随着父pl/sql block的失败而回滚,而是自己管自己commit。自治事务常用于写入LOG或TRAC信息便于查找错误。
自治事务(以下简称AT)是由主事务(以下简称MT)调用但是独立于MT的事务。在自治事务被调用执行时,MT被挂起,在自治事务内部,一系列的DML可以被执行并且commit或rollback. 自治事务防止嵌套提交,使事务在自己的事务区内提交或回滚不会影响其他的事务。由于自治事务的独立性,它的commit和rollback并不影响MT的执行效果。在自治事务执行结束后,主事务获得控制权,又可以继续执行了。
实现自治事务的定义,只需下列PL/SQL的声明部分加上PRAGMA AUTONOMOUS_TRANSACTION 就可以了。
1 顶级的匿名PL/SQL块
2 Functions 或 Procedure
3 触发器。
比如:
在一个独立的procedure中声明自治事务:
CREATE OR REPLACE PROCEDURE
   Log_error(error_msg IN VARCHAR2(100))
IS
  PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
   Insert into Error_log values ( sysdate,error_msg);
   COMMIT;
END;
 
 现在用自治事务改写一下procedure local:
create or replace procedure local is
cnt number := -1;   -- Global variables
PRAGMA AUTONOMOUS_TRANSACTION;
   begin
      select count(*) into cnt from msg;
      dbms_output.put_line('local: # of rows is '||cnt);
       
      insert into msg values ('New Record');
      commit;
   end;
 
执行第(3)步的PL/SQL匿名块,
运行结果(注意打开set serveroutput on)如下:
local: # of rows is 0 -> 子事务local中无法’看到’主匿名块中的uncommitted记录 (因为它是独立的)
main: # of rows is 2-> 主匿名块可以’看到’2条记录,但只有一条是被commited.
local: # of rows is 1 -> 子事务local中可以’看到’它前一次commit的记录,但是主匿名块中的记录已经被提前rollback了
local: # of rows is 3 -> 子事务local 中可以’看到’3条记录包括主匿名块commit的记录
main: # of rows is 4 ->主匿名块最后’看到’了所有的记录.
 
PL/SQL 过程已成功完成。
 
l       结论:
从这个例子中我们看到,在没有自制事务的情况下,COMMIT和ROLLBACK的位置无论是在主匿名块中或者在子程序中,都会影响到整个当前事务. 如果子程序中有事务或有commit语句,那么是回滚不了的,否则可以回滚,因为事务只是回滚上一个committ或rollback之后的所有事务。
在使用自制事务的情况下, AT是独立的,在它执行时,MT被暂停了. AT的COMMIT,ROLLBACK并不影响MT的执行.
运用AT时,有一些注意事项,简单列举如下:
1.     在匿名PL/SQL块中,只有顶级的匿名PL/SQL块可以被设为AT
2.     Package 不能被声明为AT,只有package所拥有的function和procedure 才能声明为AT
3.     AT程序必须以commit 或rollback结尾,否则会产生Oracle错误ORA-06519: active autonomous transaction detected and rolled back
### 事务嵌套的使用方法与行为 数据库中的 **nested transactions**(嵌套事务)是一种允许在一个事务内部启动另一个事务的功能。这种机制通常用于复杂的业务逻辑场景,其中某些操作可能需要独立提交或回滚而不影响外部事务的状态。 #### 嵌套事务的行为特点 1. 外部事务控制整体状态,而内部事务可以具有局部作用域[^2]。 2. 如果支持真正的嵌套事务,则只有当所有子事务都成功完成时,整个事务才会被标记为成功并最终提交[^3]。 3. 子事务的 `COMMIT` 并不会立即生效;它仅表示该部分工作已完成,但仍需等待父事务的整体提交才能永久化更改[^4]。 4. 若某个子事务失败并执行 `ROLLBACK`,则其修改会被撤销,但不影响其他已成功的兄弟子事务或父事务继续运行[^5]。 #### SQL Server 中的实现方式 在 Microsoft SQL Server 数据库管理系统里,通过设置 SAVEPOINT 来模拟嵌套事务的效果。SAVEPOINT 定义了一个恢复点,在此之后所做的任何变更都可以单独撤消,而无需终止整个大范围内的活动记录更新过程: ```sql BEGIN TRANSACTION OuterTran; -- Some operations here... BEGIN TRANSACTION InnerTran; INSERT INTO ExampleTable (ColumnA) VALUES ('Value'); IF @@ERROR <> 0 ROLLBACK TRANSACTION InnerTran; COMMIT TRANSACTION InnerTran; -- More actions... IF AllGood = 1 COMMIT TRANSACTION OuterTran; ELSE ROLLBACK TRANSACTION OuterTran; ``` 尽管如此,请注意并非所有的 DBMS 都完全支持标准定义下的多层次结构化的交易管理功能——比如 MySQL 默认情况下不提供严格意义上的 nested transaction 支持[^6]。 #### Oracle 的 Savepoint 方法 Oracle 提供 savepoints 作为处理复杂事务的一种手段。Savepoints 让程序员能够在长事务期间创建检查点,从而使得能够有选择性地回退到这些特定位置而不是放弃全部未保存的工作成果: ```plsql SET AUTOCOMMIT OFF; DECLARE v_error EXCEPTION; BEGIN INSERT INTO employees (...); SAVEPOINT before_bonus_update; UPDATE bonuses SET bonus=bonus*1.1 WHERE employee_id=... ; RAISE v_error; -- Simulate an error condition EXCEPTION WHEN OTHERS THEN ROLLBACK TO SAVEPOINT before_bonus_update; END; / COMMIT; ``` 以上脚本展示了如何利用 PL/SQL 编程语言结合异常处理器来构建更加健壮的应用程序逻辑流控方案[^7]。 ### 注意事项 - 不同的关系型数据库产品对于嵌套事务的支持程度存在差异,开发人员应当查阅所使用的具体产品的官方文档获取最精确的信息。 - 使用不当可能导致死锁或者资源争用等问题,因此建议谨慎设计涉及多个并发访问路径的数据操纵流程[^8]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值