KingbaseES中的ora_statement_level_rollback参数

文章概述

参数 ora_statement_level_rollback 控制KingbaseES 是否实现类似oracle 语句级的回滚。当该参数打开时,如果事务操作失败,仅会回滚触发异常的语句,避免了全部操作的回滚。默认情况下该参数为OFF,也就是说DML语句在PLSQL块中出错后默认是全部回滚:

---查看数据库默认的ora_statement_level_rollback配置为OFF
test=# show ora_statement_level_rollback
test-# /
 ORA_STATEMENT_LEVEL_ROLLBACK
------------------------------
 off
(1 row)

test=#

以下举例在不同数据库上的执行异同:

一,KES

1,开启ora_statement_level_rollback 参数测试

set ora_statement_level_rollback to on;

DROP TABLE IF EXISTS mytab CASCADE;
CREATE TABLE mytab(firstname TEXT, lastname TEXT);
INSERT INTO mytab(firstname, lastname) VALUES('Tom', 'Jones');

\set SQLTERM /
CREATE OR REPLACE PROCEDURE PROC() AS
    x int := 1;
BEGIN
    INSERT INTO mytab(firstname, lastname) VALUES('Jack', 'Ben');
    UPDATE mytab SET firstname = 'Joe' WHERE lastname = 'Jones';
    x := x / 0;
EXCEPTION
    WHEN ZERO_DIVIDE THEN
        RAISE NOTICE 'caught division_by_zero';
END;
/

调用存储过程,查看测试结果:

test=# select * from mytab;   --执行前的检查
test-# /
 FIRSTNAME | LASTNAME
-----------+----------
 Tom       | Jones
(1 row)

test=# call proc();     ----执行存储过程
test-# /
NOTICE:  caught division_by_zero
CALL

test=# select * from mytab;   --执行后的检查
test-# /
 FIRSTNAME | LASTNAME
-----------+----------
 Jack      | Ben
 Joe       | Jones
(2 rows)

test=#

可以看出,并没回滚除零异常前的DML语句。

提问:这里如果没有异常处理,会回滚update嘛?会的。

----接着上面的代码和表继续测试
\set SQLTERM /
CREATE OR REPLACE PROCEDURE PROC2() AS
    x int := 1;
BEGIN
    UPDATE mytab SET firstname = 'Lucy' WHERE lastname = 'Ben';
    x := x / 0;
END;
/

执行并查看结果:

---执行没异常处理的存储过程
test=# call proc2();
test-# /
ERROR:  division by zero
CONTEXT:  PL/SQL function proc2() line 5 at assignment

test=# select * from mytab;
test-# /
 FIRSTNAME | LASTNAME
-----------+----------
 Jack      | Ben
 Joe       | Jones
(2 rows)

test=#

可以看到,全局回滚了,UPDATE 语句执行生效。

2,关闭ora_statement_level_rollback 参数测试

先完成以下创建

set ora_statement_level_rollback to off;

DROP TABLE IF EXISTS mytab CASCADE;
CREATE TABLE mytab(firstname TEXT, lastname TEXT);
INSERT INTO mytab(firstname, lastname) VALUES('Tom', 'Jones');

\set SQLTERM /
CREATE OR REPLACE PROCEDURE PROC() AS
    x int := 1;
BEGIN
    INSERT INTO mytab(firstname, lastname) VALUES('Jack', 'Ben');
    UPDATE mytab SET firstname = 'Joe' WHERE lastname = 'Jones';
    x := x / 0;
EXCEPTION
    WHEN ZERO_DIVIDE THEN
        RAISE NOTICE 'caught division_by_zero';
END;
/

执行测试:

test=# select * from mytab;
test-# /
 FIRSTNAME | LASTNAME
-----------+----------
 Tom       | Jones
(1 row)

test=# call proc();
test-# /
NOTICE:  caught division_by_zero
CALL
test=# select * from mytab;
test-# /
 FIRSTNAME | LASTNAME
-----------+----------
 Tom       | Jones
(1 row)

可以看到,即使有exception也全局回滚,符合预期。同理执行了没有exception处理下的proc2()测试,也是全局回滚。

因此KES默认下PLSQL块中就是事务全局回滚

二,Oracle

均是在默认参数情况下测试,测试准备代码:

DROP TABLE   mytab ;
CREATE TABLE mytab(firstname varchar(20), lastname varchar(20));
INSERT INTO mytab(firstname, lastname) VALUES('Tom', 'Jones');

CREATE OR REPLACE PROCEDURE PROC AS
    x int := 1;
BEGIN
    INSERT INTO mytab(firstname, lastname) VALUES('Jack', 'Ben');
    UPDATE mytab SET firstname = 'Joe' WHERE lastname = 'Jones';
    x := x / 0;
EXCEPTION
    WHEN ZERO_DIVIDE THEN
       dbms_output.put_line('caught division_by_zero');
END;

执行测试:

call PROC();

select * from mytab;
--测试结果
Joe    Jones
Jack    Ben

和开启参数的KES一样,语句级回滚,未全局回滚。

接着测试:

---没有exception的函数PROC2
CREATE OR REPLACE PROCEDURE PROC2 AS
    x int := 1;
BEGIN
    UPDATE mytab SET firstname = 'Lucy' WHERE lastname = 'Ben';
    x := x / 0;
END;

call PROC2();

select * from mytab;
---测试结果,UPDATE 未生效,全局回滚了。
Joe    Jones
Jack    Ben

三,SqlServer

我们先把PLSQL代码翻译成SQLServer的语法,准备如下代码:

DROP TABLE IF EXISTS mytab ;
CREATE TABLE mytab(firstname varchar(20), lastname varchar(20));
INSERT INTO mytab(firstname, lastname) VALUES('Tom', 'Jones');

go
create or alter procedure proc1     ---吐槽sqlsevrer的proc是保留字,是procedure的缩写,这里不能命名为proc
as
begin
    begin tran trans1
        declare  @x int = 1
        begin try
            insert into mytab(firstname, lastname) values('jack', 'ben')
            update mytab set firstname = 'joe' where lastname = 'jones'
            set @x = @x / 0
        end try
        begin catch
            select error_line() as 错误代码行号,  
                  error_message() as 错误消息,  
                  error_number() as 错误代码
        end catch;
end;
go

执行结果:

--测试前查看结果
select * from mytab;
--执行结果
Tom    Jones

exec PROC1;  --调用存储过程

---查看执行结果
select * from mytab;
--执行结果
Joe    Jones
Jack    Ben

显然,SQLServer默认情况下是语句级回滚。

四,小结:

Oracle和SQLServer默认情况下一样,PLSQL块中是语句级回滚。KingbaseES默认情况下是全局回滚,当开启ora_statement_level_rollback为on时则和

Oracle相同,实际测试如下:

1,有exception处理时,如果事务操作失败,仅会回滚触发异常的语句,不会全部操作的回滚。

2,没有exception处理时,如果事务操作失败,会全部操作的回滚。

即可以做到和oracle默认事务控制一致

posted @ 2024-03-29 18:37  KINGBASE研究院  阅读(35)  评论(0编辑  收藏  举报