达梦事务管理之自治事务

操作系统版本CentOS7.6
数据库版本DM8_20240712

目录

1.问题与解决方案

1.1问题提出

1.2 自治事务

2.实现方法

3.不同场景的测试

3.1 测试准备

3.2 场景一:主程序的ROLLBACK会回滚日志

3.3 场景二:日志中的COMMIT会提交主程序的事务

3.4 场景三:自治事务

4.注意事项


1.问题与解决方案

1.1问题提出

        数据库事务是一种单元操作,要么是全部操作都成功,要么全部失败。

        我们可能会遇到这样的需求:在一个事务中,分步记录日志并将日志信息写入TABLE。然而,记录日志的代码与主代码在一个事务中,主代码的ROLLBACK会回滚日志DML操作,日志中的COMMIT,也会影响主代码。详见3.2节、3.3节的测试。

1.2 自治事务

         在达梦数据库中,可以定义自治事务解决上面的问题。

        通过将一个 DMSQL 语句块定义成自治事务,可以将该块中的 DML 语句和调用程序的

事务环境隔离开。如此一来,该语句块就成为一个由其他事务启动的独立的事务,前一个事

务被称为主事务。在自治事务块中,主事务是挂起的;等待自治事务完成后,会话自动切换

回主事务。

2.实现方法

定义自治事务,需要在 DMSQL 程序的声明部分添加如下语法的语句。

语法如下:

PRAGMA  AUTONOMOUS_TRANSACTION;

自治事务的定义语句可以放在 DMSQL 程序声明部分的任何地方,但推荐放在数据结构

声明之前。

作为自治事务的 DMSQL 语句块可以是下面中的一种:

 最顶层的(不是嵌套的)匿名 DMSQL 语句块

 函数和过程,或者在一个包里定义或者是一个独立的程序

 对象类型的方法

 数据库触发器

 嵌套子过程

实现方法举例:见3.4节与3.1节代码。

3.不同场景的测试

3.1 测试准备

(1)准备2张表:TB_TEST01存放数据、TB_LOG存放日志。

CREATE TABLE TB_TEST01(
C_DT	DATETIME,
C_DATA  VARCHAR(50),
C_SESSID  BIGINT,  -- 会话ID
C_TID     BIGINT   -- 事务ID
);

CREATE TABLE TB_LOG(
C_DT	DATETIME,
C_LOG  VARCHAR(50),
C_SESSID  BIGINT,  -- 会话ID
C_TID     BIGINT   -- 事务ID
);

(2)准备3个存储过程用来记录日志或错误信息

P_LOG_COMMIT //存过中使用COMMIT

P_LOG_UNCOMMIT //存过中不使用COMMIT也不使用ROLLBACK

P_LOG_AUTONOMOUS //自治事务

--存过中使用COMMIT
CREATE OR REPLACE PROCEDURE P_LOG_COMMIT(V_LOG VARCHAR(50))
IS
BEGIN
	INSERT INTO TB_LOG(C_DT,C_LOG,C_SESSID,C_TID)
	SELECT SYSDATE(),V_LOG,SESSID,ID FROM SYS.V$TRX T WHERE T.SESS_ID=SESSID;
	COMMIT;
END;

--存过中不使用COMMIT也不使用ROLLBACK
CREATE OR REPLACE PROCEDURE P_LOG_UNCOMMIT(V_LOG VARCHAR(50))
IS
BEGIN
	INSERT INTO TB_LOG(C_DT,C_LOG,C_SESSID,C_TID)
	SELECT SYSDATE(),V_LOG,SESSID,ID FROM SYS.V$TRX T WHERE T.SESS_ID=SESSID;
END;

--自治事务
CREATE OR REPLACE PROCEDURE P_LOG_AUTONOMOUS(V_LOG VARCHAR(50))
IS
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
	INSERT INTO TB_LOG(C_DT,C_LOG,C_SESSID,C_TID)
	SELECT SYSDATE(),V_LOG,SESSID,ID FROM SYS.V$TRX T WHERE T.SESS_ID=SESSID;
	COMMIT;
END;

3.2 场景一:主程序的ROLLBACK会回滚日志

场景一使用存过P_LOG_UNCOMMIT记录日志,这个存过中没有COMMIT也没有ROLLBACK。

(1)清空数据

DELETE FROM TB_TEST01;
DELETE FROM TB_LOG;
COMMIT;

(2)执行代码块

BEGIN
	INSERT INTO TB_TEST01(C_DT,C_DATA,C_SESSID,C_TID)
	SELECT SYSDATE(),'主程序:主程序的ROLLBACK会回滚日志',SESSID,ID FROM SYS.V$TRX T WHERE T.SESS_ID=SESSID;  -- 1.主程序写入一条数据
	P_LOG_UNCOMMIT('日志:主程序的ROLLBACK会回滚日志'); -- 2.用存过记录日志
	ROLLBACK; -- 3.回滚
END;

(3)查询结果

小结:日志写入失败。主程序的ROLLBACK回滚了存过P_LOG_UNCOMMIT中的INSERT操作。

3.3 场景二:日志中的COMMIT会提交主程序的事务

场景二使用存过P_LOG_COMMIT记录日志,这个存过中有COMMIT语句,详见3.1节存过代码。

(1)清空数据

DELETE FROM TB_TEST01;
DELETE FROM TB_LOG;
COMMIT;

(2)执行代码块

BEGIN
	INSERT INTO TB_TEST01(C_DT,C_DATA,C_SESSID,C_TID)
	SELECT SYSDATE(),'主程序1:日志中的COMMIT会提交主程序的事务',SESSID,ID FROM SYS.V$TRX T WHERE T.SESS_ID=SESSID; -- 1.主程序写入第1条数据
	P_LOG_COMMIT('日志:日志中的COMMIT会提交主程序的事务'); --2.用存过记录日志
	INSERT INTO TB_TEST01(C_DT,C_DATA,C_SESSID,C_TID)
	SELECT SYSDATE(),'主程序2:日志中的COMMIT会提交主程序的事务',SESSID,ID FROM SYS.V$TRX T WHERE T.SESS_ID=SESSID; --3. 主程序写入第2条数据
	ROLLBACK; --4.回滚
END;

(3)查询结果

SELECT * FROM TB_TEST01;
SELECT * FROM TB_LOG;

小结:主程序ROLLBACK失败。存过P_LOG_COMMIT中的COMMIT提交了第1个INSERT。从查询截图也可以看出,存过P_LOG_COMMIT的事务ID与主程序中第1条INSERT的事务ID是一样的。

3.4 场景三:自治事务

场景三使用存过P_LOG_AUTONOMOUS记录日志,这个存过定义了自治事务,详见3.1节存过代码。

(1)清空数据

DELETE FROM TB_TEST01;
DELETE FROM TB_LOG;
COMMIT;

(2)执行代码块

BEGIN
	INSERT INTO TB_TEST01(C_DT,C_DATA,C_SESSID,C_TID)
	SELECT SYSDATE(),'主程序:自治事务',SESSID,ID FROM SYS.V$TRX T WHERE T.SESS_ID=SESSID;
	P_LOG_AUTONOMOUS('日志:自治事务');
	ROLLBACK;
END;

(3)查询结果

SELECT * FROM TB_TEST01;
SELECT * FROM TB_LOG;

小结:日志写入成功,主程序ROLLBACK成功。从日志中还可以看出,会话134037224中,主程序与日志存过是2个不同事务,事务号分别是277067和277068。

4.注意事项

        自治事务相对主事务是完全独立的。由于执行自治事务时主事务处于挂起状态,如果自

治事务需要的锁资源已经被主事务拥有则会产生死锁报错。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值