海量智库第31期 | 自治事务原理与应用解析
在复杂的数据库应用环境中,事务管理常面临一大难题:
如何在保证主事务逻辑连续性的同时,执行那些需要独立控制的事务操作,如日志记录、错误处理和异步通知等。这些操作若与主事务绑定,可能会增加处理的复杂性。
自治事务由此应运而生,它提供了在主事务外独立进行事务处理的能力,成为解决这一难题的关键。
自治事务是什么?
自治事务(Autonomous Transactions)是Oracle原生支持的一种特殊事务类型,指在PL/SQL中可以启动一个与主事务隔离的事务,这个事务可以提交(COMMIT)或回滚(ROLLBACK)而不影响主事务。该功能可以在PL/pgSQL的函数(Function)或存储过程(Stored Procedure)中应用,使得当前存储过程中的事务可以独立提交,而不会影响到外部事务。
在Oracle中,可以通过PRAGMA AUTONOMOUS_TRANSACTION声明来创建自治事务。
自治事务通常用于需要独立于主事务执行数据库操作的场景,比如发送日志信息到数据库表而不影响主事务的完整性。
自治事务实现原理
语法说明
plpgsql_call_handler:为plsql函数的调用入口
plpgsql_compile:为进行函数编译
plpgsql_exec_function:为根据函数的编译结果来执行函数
自治事务核心逻辑
-
自治事务编译时,会在func中打上自治事务标记
-
当自治事务函数被调用时,会在主线程的函数执行阶段启动自治事务线程
-
从主线程传递自治事务函数执行所需要的参数和数据
-
自治事务线程通过执行算子来执行自治事务函数
-
自治事务函数执行后返回结果到主线程
自治事务的特点
1.隔离操作
自治事务可以独立于外部事务进行提交或回滚,从而不会对外部事务造成影响。
2.错误处理
自治事务可以捕获和处理异常,而不会导致外部事务中止。
3.复用代码
自治事务可以被多个事务重复调用而不会相互干扰。
4.性能优化
自治事务可以显著提高模块化和复用代码的性能。
示例代码:
CREATE OR REPLACE PROCEDURE outer_procedure IS
BEGIN
-- 外部事务的操作
INSERT INTO outer_table VALUES (1);
-- 调用自治事务
inner_procedure;
COMMIT;
EXCEPTION
WHEN OTHERS THEN
ROLLBACK;
RAISE;
END outer_procedure;
CREATE OR REPLACE PROCEDURE inner_procedure IS
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
-- 自治事务的操作
INSERT INTO inner_table VALUES (2);
-- 可以包含自己的提交和回滚逻辑
COMMIT;-- 自治事务内的提交不会影响到外部事务
EXCEPTION
WHEN OTHERS THEN
ROLLBACK;-- 自治事务内的异常处理不会影响到外部事务
RAISE;
END inner_procedure;
在这个例子中,outer_procedure 和 inner_procedure 分别展示了外部事务和自治事务的操作。
package中的自治事务
package(包)是将逻辑上相关的PL/SQL存储过程、函数、类型、变量、游标等封装在一起的单元。
在package中定义的自治事务函数或自治事务过程,其自治事务处理的能力与它们作为独立对象时是一致的。
由于在package中定义的变量状态是会话(Session)级别的,而会话状态与事务的提交/回滚状态无关,因此若主事务或自治事务修改package的变量时,该修改会立即反映在当前会话里的所有事务中,包括主事务和自治事务。
自治事务在package中的应用可以使在复杂的数据库应用程序中灵活地共享和管理状态信息。
示例场景:
以在package中声明自治事务为例:
1.创建测试表
create table tb_1188082 (id int);
2.创建包
CREATE OR REPLACE PACKAGE pkg_1188082 is
function pkg_1188082_fun1(i int) return int;
function pkg_1188082_fun2(i int) return int;
id1 int:= 1;
end pkg_1188082;
/
3.创建包体,在包体定义两个函数并声明自治事务
CREATE OR REPLACE PACKAGE BODY pkg_1188082 is
function pkg_1188082_fun1(i int) return int is
res int;
PRAGMA AUTONOMOUS_TRANSACTION; --声明了自主事务,这意味着pkg_1188082_fun1函数内部的SQL操作将在一个独立的事务中执行
begin
insert into tb_1188082 values(id1);
rollback;
insert into tb_1188082 values(i+id1);
commit;
res:=id1;
return res;
end;
function pkg_1188082_fun2(i int) return int is
res int;
PRAGMA AUTONOMOUS_TRANSACTION; ----声明了自主事务
begin
insert into tb_1188082 values(i+id1);
res := i;
return res;
commit;
end;
begin
id1 := 2;
end pkg_1188082;
/
4.调用包函数
select pkg_1188082.pkg_1188082_fun1(10) from dual;
select * from tb_1188082;
select pkg_1188082.pkg_1188082_fun2(100) from dual;
select * from tb_1188082;
返回结果分别为:
复制代码
pkg_1188082_fun1
-----------------
2
(1 row)
id
----
12
(1 row)
pkg_1188082_fun2
-----------------
100
(1 row)
id
----
12
102
(2 rows)
开发中的关键函数解析
1.plpgsql_exec_autonomous_function
该函数在plsql function执行阶段plpgsql_exec_function中被调用。主要作用是启动自治事务线程,接收自治事务的返回结果,以及结束之后的清理。分别对应的函数为pg_background_launch,TupleQueueReaderNext,pg_background_end。
2.pg_background_launch
该函数的主要作用是,建立主事务和自治事务之间的共享内存,用来传递参数,保存结果,以及进行错误消息处理。
主事务和自治事务之间传递参数的结构体为:
其中变量dsa_shared_object是基于dsa来进行的共享内存管理,实现FunctionCallInfo信息在主事务和自治事务进行共享,主事务通过SharedFunctionCallInfo将该信息存储到共享内存,自治事务通过RestoreFunctionCallInfo从共享内存中获取该信息。
共享内存初始化之后,通过RegisterDynamicBackgroundWorker来注册自治事务线程。
3.ExecAutonomousFunction
自治事务的执行是在函数worker_run_autonomous_transaction中进行,使用了执行算子的机制。初始化函数为ExecInitExecAutonomousFunc,执行函数为ExecAutonomousFunction,结束函数为ExecEndExecAutonomousFunc。
Vastbase应用自治事务优势
在Vastbase代码开发实践中,自治事务的使用带来了诸多显著优势。
它实现了主线程与自治事务线程的同步并行,显著增强了系统的并发处理能力,促进了两者之间的无缝通信与数据同步。
面对异常情况,主事务与自治事务能够独立处理各自的异常,这种隔离机制有效减少了系统间的相互干扰,确保了系统的稳定运行,防止了因单个事务异常而引发的全局性故障。
此外,自治事务还优化了内存管理机制,通过改进dsm和dsa技术,由ResourceOwner自动释放共享内存,杜绝了heap-use-after-free的风险。同时,自治事务的执行依赖于高效的执行算子机制,使得函数执行流程更加清晰明了,执行效率也随之提升。