自治事務(wù)是由調(diào)用程序啟動的獨(dú)立事務(wù)。自治事務(wù)中SQL命令的提交或回滾對調(diào)用程序的任何事務(wù)中的提交或回滾都沒有影響。調(diào)用程序中的提交或回滾對自治事務(wù)中SQL命令的提交或回滾也沒有影響。

通過在SPL塊的聲明部分中指定以下指令,可將SPL程序聲明為自治事務(wù):

PRAGMA AUTONOMOUS_TRANSACTION;

以下SPL程序可包含 PRAGMA AUTONOMOUS_TRANSACTION:

  • 獨(dú)立的存儲過程和函數(shù)。
  • 匿名塊。
  • 包中聲明為子程序的存儲過程和函數(shù)以及其他調(diào)用存儲過程、函數(shù)和匿名塊。
  • 觸發(fā)器。
  • 對象類型方法。

下面是與自治事務(wù)有關(guān)的問題和限制:

  • 每個自治事務(wù)只要在進(jìn)行中,就會消耗一個連接槽。在某些情況下,這可能意味著應(yīng)增大postgresql.conf文件中的max_connections參數(shù)。
  • 在大多數(shù)方面,自治事務(wù)的行為就像是一個完全獨(dú)立的會話,但GUC(即通過SET建立的設(shè)置)是一個有意制造的例外。自治事務(wù)吸收周圍的值,并可以將它們提交的值傳播到外部事務(wù)。
  • 自治事務(wù)可以嵌套,但在單個會話中自治事務(wù)的嵌套級別限制為16級。
  • 自治事務(wù)中不支持并行查詢。
  • 自治事務(wù)的PolarDB PostgreSQL版(兼容Oracle)實(shí)現(xiàn)與Oracle數(shù)據(jù)庫不完全兼容,因?yàn)槿绻鸖PL塊末尾有未提交的事務(wù),則PolarDB PostgreSQL版(兼容Oracle)自治事務(wù)不會產(chǎn)生錯誤。

以下一組示例闡釋了自治事務(wù)的用法。第一組場景顯示了沒有自治事務(wù)時的默認(rèn)行為。

在每個場景之前,dept表重置為以下初始值:

SELECT * FROM dept;

 deptno |   dname    |   loc
--------+------------+----------
     10 | ACCOUNTING | NEW YORK
     20 | RESEARCH   | DALLAS
     30 | SALES      | CHICAGO
     40 | OPERATIONS | BOSTON
(4 rows)    

場景

  • 場景1a:沒有自治事務(wù),只有最終COMMIT

    第一組場景顯示了如何插入三行,首先就從事務(wù)的初始BEGIN命令之后開始插入第一行,然后從起始事務(wù)的匿名塊插入第二行,最后從匿名塊內(nèi)執(zhí)行的存儲過程插入第三行。

    該存儲過程如下:

    CREATE OR REPLACE PROCEDURE insert_dept_70 IS
    BEGIN
        INSERT INTO dept VALUES (70,'MARKETING','LOS ANGELES');
    END;

    PSQL會話如下:

    BEGIN;
    INSERT INTO dept VALUES (50,'HR','DENVER');
    BEGIN
        INSERT INTO dept VALUES (60,'FINANCE','CHICAGO');
        insert_dept_70;
    END;
    COMMIT;

    在最后提交后,將插入所有三行:

    SELECT * FROM dept ORDER BY 1;
    
     deptno |   dname    |     loc
    --------+------------+-------------
         10 | ACCOUNTING | NEW YORK
         20 | RESEARCH   | DALLAS
         30 | SALES      | CHICAGO
         40 | OPERATIONS | BOSTON
         50 | HR         | DENVER
         60 | FINANCE    | CHICAGO
         70 | MARKETING  | LOS ANGELES
    (7 rows)
  • 場景1b:沒有自治事務(wù),但有最終ROLLBACK

    下一個場景顯示,所有插入之后的最后一個ROLLBACK命令將導(dǎo)致所有三個插入的回滾:

    BEGIN;
    INSERT INTO dept VALUES (50,'HR','DENVER');
    BEGIN
        INSERT INTO dept VALUES (60,'FINANCE','CHICAGO');
        insert_dept_70;
    END;
    ROLLBACK;
    
    SELECT * FROM dept ORDER BY 1;
    
     deptno |   dname    |   loc
    --------+------------+----------
         10 | ACCOUNTING | NEW YORK
         20 | RESEARCH   | DALLAS
         30 | SALES      | CHICAGO
         40 | OPERATIONS | BOSTON
    (4 rows)
  • 場景1c:沒有自治事務(wù),但有匿名塊ROLLBACK

    匿名塊結(jié)尾給出的ROLLBACK命令也消除了所有以前的三個插入:

    BEGIN;
    INSERT INTO dept VALUES (50,'HR','DENVER');
    BEGIN
        INSERT INTO dept VALUES (60,'FINANCE','CHICAGO');
        insert_dept_70;
        ROLLBACK;
    END;
    COMMIT;
    
    SELECT * FROM dept ORDER BY 1;
    
     deptno |   dname    |   loc
    --------+------------+----------
         10 | ACCOUNTING | NEW YORK
         20 | RESEARCH   | DALLAS
         30 | SALES      | CHICAGO
         40 | OPERATIONS | BOSTON
    (4 rows)

    下一組場景顯示了在不同位置使用PRAGMA AUTONOMOUS_TRANSACTION自治事務(wù)的效果。

  • 場景2a:帶有COMMIT的匿名塊的自治事務(wù)

    存儲過程保持最初創(chuàng)建的樣子:

    CREATE OR REPLACE PROCEDURE insert_dept_70 IS
    BEGIN
        INSERT INTO dept VALUES (70,'MARKETING','LOS ANGELES');
    END;

    現(xiàn)在,PRAGMA AUTONOMOUS_TRANSACTION通過匿名塊給出,并且匿名塊末尾給出COMMIT命令。

    BEGIN;
    INSERT INTO dept VALUES (50,'HR','DENVER');
    DECLARE
        PRAGMA AUTONOMOUS_TRANSACTION;
    BEGIN
        INSERT INTO dept VALUES (60,'FINANCE','CHICAGO');
        insert_dept_70;
        COMMIT;
    END;
    ROLLBACK;    

    在事務(wù)結(jié)束時執(zhí)行ROLLBACK后,只丟棄了事務(wù)開始時的第一行插入。帶有PRAGMA AUTONOMOUS_TRANSACTION的匿名塊中的另兩行插入已獨(dú)立提交。

    SELECT * FROM dept ORDER BY 1;
    
     deptno |   dname    |     loc
    --------+------------+-------------
         10 | ACCOUNTING | NEW YORK
         20 | RESEARCH   | DALLAS
         30 | SALES      | CHICAGO
         40 | OPERATIONS | BOSTON
         60 | FINANCE    | CHICAGO
         70 | MARKETING  | LOS ANGELES
    (6 rows)
  • 場景2b:帶有COMMIT的自治事務(wù)匿名塊包含帶有ROLLBACK的存儲過程,而不是自治事務(wù)過程

    現(xiàn)在,存儲過程在末尾具有ROLLBACK命令。但是,您會看到PRAGMA ANONYMOUS_TRANSACTION未包含在此存儲過程中。

    CREATE OR REPLACE PROCEDURE insert_dept_70 IS
    BEGIN
        INSERT INTO dept VALUES (70,'MARKETING','LOS ANGELES');
        ROLLBACK;
    END;

    現(xiàn)在,該存儲過程中的回滾會在匿名塊中的最終COMMIT命令之前刪除匿名塊中插入的兩行(deptno 60和70)。

    BEGIN;
    INSERT INTO dept VALUES (50,'HR','DENVER');
    DECLARE
        PRAGMA AUTONOMOUS_TRANSACTION;
    BEGIN
        INSERT INTO dept VALUES (60,'FINANCE','CHICAGO');
        insert_dept_70;
        COMMIT;
    END;
    COMMIT;

    在事務(wù)結(jié)束時進(jìn)行最終提交之后,插入的唯一一行是事務(wù)開始時插入的第一行。由于匿名塊是自治事務(wù),因此封閉存儲過程中的回滾對執(zhí)行匿名塊之前發(fā)生的插入沒有影響。

    SELECT * FROM dept ORDER by 1;
    
     deptno |   dname    |   loc
    --------+------------+----------
         10 | ACCOUNTING | NEW YORK
         20 | RESEARCH   | DALLAS
         30 | SALES      | CHICAGO
         40 | OPERATIONS | BOSTON
         50 | HR         | DENVER
    (5 rows)
  • 場景2c :帶有COMMIT的自治事務(wù)匿名塊包含帶ROLLBACK的存儲過程,該過程也是自治事務(wù)過程

    現(xiàn)在,在末尾具有ROLLBACK命令的存儲過程也包含PRAGMA ANONYMOUS_TRANSACTION。這將隔離該存儲過程中ROLLBACK命令的效果。

    CREATE OR REPLACE PROCEDURE insert_dept_70 IS
        PRAGMA AUTONOMOUS_TRANSACTION;
    BEGIN
        INSERT INTO dept VALUES (70,'MARKETING','LOS ANGELES');
        ROLLBACK;
    END;

    現(xiàn)在,該存儲過程中的回滾會刪除由該過程插入的行,而不是在匿名塊中插入的其他行。

    BEGIN;
    INSERT INTO dept VALUES (50,'HR','DENVER');
    DECLARE
        PRAGMA AUTONOMOUS_TRANSACTION;
    BEGIN
        INSERT INTO dept VALUES (60,'FINANCE','CHICAGO');
        insert_dept_70;
        COMMIT;
    END;
    COMMIT;

    在事務(wù)結(jié)束時進(jìn)行最終提交后,插入的行是從事務(wù)開始時插入的第一行,以及在匿名塊開始時插入的行。回滾的唯一插入是該存儲過程中的插入。

    SELECT * FROM dept ORDER by 1;
    
     deptno |   dname    |   loc
    --------+------------+----------
         10 | ACCOUNTING | NEW YORK
         20 | RESEARCH   | DALLAS
         30 | SALES      | CHICAGO
         40 | OPERATIONS | BOSTON
         50 | HR         | DENVER
         60 | FINANCE    | CHICAGO
    (6 rows)

    現(xiàn)在,以下各節(jié)顯示了一系列其他SPL程序類型中的PRAGMA AUTONOMOUS_TRANSACTION的示例。

自治事務(wù)觸發(fā)器

以下示例顯示了使用PRAGMA AUTONOMOUS_TRANSACTION聲明觸發(fā)器的效果。

下表是為了記錄對emp表的更改而創(chuàng)建的:

CREATE TABLE empauditlog (
    audit_date      DATE,
    audit_user      VARCHAR2(20),
    audit_desc      VARCHAR2(20)
);

附加到emp表并將這些更改插入empauditlog表的觸發(fā)器如下:您會看到,在聲明部分中包含了PRAGMA AUTONOMOUS_TRANSACTION。

CREATE OR REPLACE TRIGGER emp_audit_trig
    AFTER INSERT OR UPDATE OR DELETE ON emp
DECLARE
    PRAGMA AUTONOMOUS_TRANSACTION;
    v_action        VARCHAR2(20);
BEGIN
    IF INSERTING THEN
        v_action := 'Added employee(s)';
    ELSIF UPDATING THEN
        v_action := 'Updated employee(s)';
    ELSIF DELETING THEN
        v_action := 'Deleted employee(s)';
    END IF;
    INSERT INTO empauditlog VALUES (SYSDATE, USER,
        v_action);
END;

在BEGIN命令啟動的事務(wù)中執(zhí)行了以下兩個插入到emp表的操作。

BEGIN;
INSERT INTO emp VALUES (9001,'SMITH','ANALYST',7782,SYSDATE,NULL,NULL,10);
INSERT INTO emp VALUES (9002,'JONES','CLERK',7782,SYSDATE,NULL,NULL,10);

下面顯示了emp表中的兩個新行以及empauditlog表中的兩個條目:

SELECT * FROM emp WHERE empno > 9000;

 empno | ename |   job   | mgr  |      hiredate      | sal | comm | deptno
-------+-------+---------+------+--------------------+-----+------+--------
  9001 | SMITH | ANALYST | 7782 | 23-AUG-18 07:12:27 |     |      |     10
  9002 | JONES | CLERK   | 7782 | 23-AUG-18 07:12:27 |     |      |     10
(2 rows)

SELECT TO_CHAR(AUDIT_DATE,'DD-MON-YY HH24:MI:SS') AS "audit date",
    audit_user, audit_desc FROM empauditlog ORDER BY 1 ASC;

     audit date     |  audit_user  |    audit_desc
--------------------+--------------+-------------------
 23-AUG-18 07:12:27 | polardb      | Added employee(s)
 23-AUG-18 07:12:27 | polardb      | Added employee(s)
(2 rows)

但隨后在此會話期間給出了ROLLBACK命令。emp表不再包含這兩行,而empauditlog表仍包含其兩個條目,這是因?yàn)橛|發(fā)器隱式執(zhí)行了提交,并且PRAGMA AUTONOMOUS_TRANSACTION提交這些更改的操作獨(dú)立于調(diào)用事務(wù)中給出的回滾。

ROLLBACK;

SELECT * FROM emp WHERE empno > 9000;

 empno | ename | job | mgr | hiredate | sal | comm | deptno
-------+-------+-----+-----+----------+-----+------+--------
(0 rows)

SELECT TO_CHAR(AUDIT_DATE,'DD-MON-YY HH24:MI:SS') AS "audit date",
    audit_user, audit_desc FROM empauditlog ORDER BY 1 ASC;

     audit date     |  audit_user  |    audit_desc
--------------------+--------------+-------------------
 23-AUG-18 07:12:27 | polardb      | Added employee(s)
 23-AUG-18 07:12:27 | polardb      | Added employee(s)
(2 rows)

自治事務(wù)對象類型方法

以下示例顯示了使用PRAGMAAUTONOMOUS_TRANSACTION聲明對象方法的效果。

將創(chuàng)建以下對象類型和對象類型主體。對象類型主體中的成員存儲過程包含聲明部分中的PRAGMA AUTONOMOUS_TRANSACTION以及位于存儲過程結(jié)尾的COMMIT。

CREATE OR REPLACE TYPE insert_dept_typ AS OBJECT (
    deptno          NUMBER(2),
    dname           VARCHAR2(14),
    loc             VARCHAR2(13),
    MEMBER PROCEDURE insert_dept
);

CREATE OR REPLACE TYPE BODY insert_dept_typ AS
    MEMBER PROCEDURE insert_dept
    IS
        PRAGMA AUTONOMOUS_TRANSACTION;
    BEGIN
        INSERT INTO dept VALUES (SELF.deptno,SELF.dname,SELF.loc);
        COMMIT;
    END;
END;

在以下匿名塊中,將執(zhí)行一個插入到dept表的操作,然后調(diào)用對象的insert_dept方法,最后在匿名塊中執(zhí)行ROLLBACK命令。

BEGIN;
DECLARE
    v_dept          INSERT_DEPT_TYP :=
                      insert_dept_typ(60,'FINANCE','CHICAGO');
BEGIN
    INSERT INTO dept VALUES (50,'HR','DENVER');
    v_dept.insert_dept;
    ROLLBACK;
END;

由于insert_dept已聲明為自治事務(wù),因此其插入的部門編號60仍位于表中,但回滾刪除了插入的部門50。

SELECT * FROM dept ORDER BY 1;

 deptno |   dname    |   loc
--------+------------+----------
     10 | ACCOUNTING | NEW YORK
     20 | RESEARCH   | DALLAS
     30 | SALES      | CHICAGO
     40 | OPERATIONS | BOSTON
     60 | FINANCE    | CHICAGO
(5 rows)