写点什么

浅析金仓数据库 KingbaseES 自治事务

作者:金仓技术
  • 2025-04-30
    四川
  • 本文字数:3178 字

    阅读完需:约 10 分钟

浅析金仓数据库KingbaseES自治事务


在当今数字化时代,数据库技术不断演进,为企业提供了更高效的数据管理和处理手段。数据库自治事务作为一项新兴技术,引起了业界的广泛关注。本文将深入探讨 KingbaseES 数据库自治事务的概念、使用方法以及适用场景。


KingbaseES 自治事务核心概念

事务具有原子性,要么全部成功,要么全部失败,事务一旦失败数据库将回滚该事务内所有的数据。由于事务的这种特性将导致程序的异常信息无法记录到用户表中,从而使得用户很难判断出产生异常的原因。因此,用户急切的需要一种能够解决该问题的技术,自治事务随之应运而生。

自治事务指的是在当前事务(主事务)上开启的另一个完全独立的事务,执行自治事务程序时,主事务将挂起,退出自治事务,主事务会继续,因此,就时间线而言,主事务启动自治事务后会暂时挂起,等待自治事务执行完毕后才再次运行。类似的子事务也具有相同的时间序,但是自治事务和主事务有本质的区别,表 1 中介绍了两者之间的区别。

表 1 自治事务与子事务的区别


相比之下,自治事务启动后,是完全独立的,它与主事务不共享锁、资源或提交依赖项。即使主事务回滚,也可以记录事件、增加重置计数器等,自治事务还能够构建模块化、可重复使用的软件组件

KingbaseES 自治事务操作流程

为了更好地理解和应用数据库自治事务,本节将具体说明如何使用自治事务。

要想在应用程序中使用自治事务,需在程序声明部分使用 PRAGMA AUTONOMOUS_TRANSACTION 语句。自治事务的本质也是一个事务,所以自治事务可以 commit 和 rollback。自治事务程序正常执行结束,自治事务内执行的所有的操作会被提交并持久化;如果自治事务抛出异常,那么主事务能够捕获其抛出异常,然后用户可能根据其异常进行相应处理。

PL/SQL 对象有匿名块、函数和存储过程、包中函数和存储过程、嵌套子函数和存储过程以及触发器,自治事务可以在任意的 PLSQL 对象中使用。接下来将结合具体示例说明在不同 PLSQL 对象下如何使用自治事务。

匿名块中使用自治事务:

create table accounts (
account_id number(6),
balance number(10,2)
);
insert into accounts values (7715, 6350.00);
insert into accounts values (7720, 5100.50);


declare
pragma autonomous_transaction;
emp_id number(6) := 7715;
amount NUMBER(6, 2) := 200;
begin
update accounts set balance = balance - amount where account_id = emp_id;
commit;
end;
/
复制代码


子程序中使用自治事务

create or replace function f_lower_salary(
emp_id number, amount number) return int as
pragma autonomous_transaction;
x accounts%rowtype;
begin
update accounts set balance = balance - amount where account_id = emp_id;
select * into x from accounts where account_id = emp_id;
dbms_output.put_line('lower_salary1' || x.account_id || '-' || x.balance);
commit;
return 0;
end;
/
复制代码


包中使用自治事务

 

create or replace package emp_actions authid definer as
function raise_salary (emp_id number, sal_raise number) return number;
end emp_actions;
/
create or replace package body emp_actions as
function raise_salary (emp_id number, sal_raise number) return number as
pragma autonomous_transaction;
new_sal number(8,2);
begin
update accounts set balance = balance + sal_raise where account_id = emp_id;
commit;
select balance into new_sal from accounts where account_id = emp_id;
return new_sal;
end raise_salary;
end emp_actions;
/
复制代码


触发器中使用自治事务

create table log_accounts(
log_id number(6),
up_date date,
new_sal number(8,2),
old_sal number(8,2)
);
create or replace trigger log_sal
before update of balance on accounts for each row
declare
pragma autonomous_transaction;
begin
insert into log_accounts values (
:old.account_id,
sysdate,
:new.balance,
:old.balance
);
commit;
end;
/
复制代码


通过上述示例可以明确一点——普通用户程序仅需要在使用对象的声明区域加上声明语句 PRAGMA AUTONOMOUS_TRANSACTION 就可以使用自治事务。需要注意的是匿名块中使用自治事务,该匿名块必须为顶层的匿名块;包本身不能直接使用自治事务,但是可以在包中的子程序中使用自治事务。

数据库自治事务适用场景

因为自治事务能独立地被提交,而不影响主事务,所以自治事务可以用来做独立的数据处理。基于此,自治事务可以用于错误日志记录、数据库审计等场景

如果主事务所在的程序抛出异常,而我们想要记录该异常信息,直接使用 INSERT 语句向日志表中插入此异常信息显然是行不通的,因为如果触发了事务回滚将导致该条日志信息被清理。所以在这种情况下使用自治事务就能到达独立记录错误日志信息的目的。

如图表所示,主事务 UPDATE 操作执行完成后,再进行 fetch into 时未读到数据,此时 name 为空,进入异常处理块,然后调用程序 write_err_log 开启自治事务,挂起主事务,等待自治事务程序 write_err_log 将错误信息插入到日志表 err_log 中,结束自治事务,主事务继续,由于主事务已经出错并且事务并未提交,所以 test 表中的数据将被回滚。由此可见,自治事务很适合做独立的数据处理,特别是用于记录错误日志。

自治事务记录错误日志示例

create table account(id int, name varchar2(20), age int);create table err_log(time date, err_msg text);insert into account values(1,'zhangsan', 20);--创建自治事务\set SQLTERM /Create or replace procedure write_err_log(err_msg text) as 	PRAGMA AUTONOMOUS_TRANSACTION;Begin	insert into err_log values(sysdate, err_msg); 	commit;End;/--主事务执行存储过程CREATE OR REPLACE procedure select_nameAS    name varchar2(20);    past_due EXCEPTION; -- declare exception    cur cursor is select name from account where age = 20;Begin    Update account set age = 21 where id = 1;    open cur;    fetch cur into name;    close cur;    If name is NULL THEN        RAISE past_due;    END IF;Exception    When past_due Then        call write_err_log(sqlerrm);End;/call select_name()/--运行结果:主事务进行的UPDATE操作由于异常进行回滚,自治事务记录错误信息
复制代码



图 1 自治事务记录错误日志

数据库自治事务的限制

由于自治事务与主事务锁不共享,所以自治事务与主事务访问同一行时,由于产生资源竞争,形成死锁而出发异常,因此自治事务不适合用于该场景。

自治事务与主事务的死锁场景

create table table_name(I int,x int);
insert into table_name values(1,1);
--自治事务控制的一个存储过程
\set SQLTERM /
Create or replace procedure pt1(a int) as
PRAGMA AUTONOMOUS_TRANSACTION;
Begin
Update table_name set I = a where x = 1;
commit;
End;
/
--主事务执行如下存储过程
CREATE OR REPLACE procedure update_i
AS
Begin
    Update table_name set I = 5 where x = 1;
    pt1(3);
End;
/
call update_i();
/
--运行结果
复制代码


在示例中,主事务程序更新表 t 中的一条数据,但是未提交更改,且等待着自治事务程序的返回;自治事务程序也在更新表 t 中的同一条数据,并且提交。这种情况下,主事务未提交且主事务对该行加的锁并未释放,如果在此时自治事务想要申请该行的锁,就会形成死锁。因此自治事务不适合用于需要操作共享数据的场景。

结束语

KingbaseES 自治事务技术已经成功地应用于错误日志记录和数据库审计,随着金仓数据库在各行各业中的广泛应用,自治事务的应用场景也在不断增加,它在数据管理领域的重要性也日益凸显,将不断推动数据管理向更智能、高效的方向发展。

用户头像

金仓技术

关注

数据库平替用金仓 2025-03-24 加入

还未添加个人简介

评论

发布
暂无评论
浅析金仓数据库KingbaseES自治事务_KingBase_金仓技术_InfoQ写作社区