暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

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

数据猿 2025-04-30
163

 


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

KingbaseES自治事务核心概念

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

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

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

  事务性质

自治事务

子事务

与主事务的独立性

资源不共享

提交和回滚互不影响

在同一个session里执行,共享资源

提交和回滚会相互影响

可见性

主事务仅已提交的对自治是事务可见

自治事务的提交对主事务可见由隔离级别决定

主事务的所有更改对子事务可见

子事务的所有更改对主事务可见

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

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

  

「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论