事务管理

在调用存储过程以及匿名块中,支持用命令COMMIT和ROLLBACK结束事务。在一个事务中使用这些命令后,一个新的事务会被自动开启,不需要单独使用START TRANSACTION命令(注意BEGIN和END在PL/SQL中有不同的含义),同时不支持在用户显示开启的事务块中调用带有事务命令的存储过程或者匿名块。

下面是一个简单的例子:

  1. CREATE TABLE test1 (a int);
  2. CREATE PROCEDURE transaction_test1()
  3. AS
  4. BEGIN
  5. FOR i IN 0..9 LOOP
  6. INSERT INTO test1 (a) VALUES (i);
  7. IF i % 2 = 0 THEN
  8. COMMIT;
  9. ELSE
  10. ROLLBACK;
  11. END IF;
  12. END LOOP;
  13. END;
  14. /
  15. CALL transaction_test1();

新事务开始时具有默认事务特征,如事务隔离级别。

函数调用中不支持对事务的控制,如果在函数中试图使用事务控制,将直接报错。同时对于proc1()->func2()->proc3()这类嵌套使用,最后一个存储过程不能做事务控制,因为中间有函数的调用。

对于游标循环有特殊的考虑。如下面例子

  1. CREATE PROCEDURE transaction_test2()
  2. AS
  3. DECLARE
  4. r RECORD;
  5. BEGIN
  6. FOR r IN SELECT * FROM test2 ORDER BY x LOOP
  7. INSERT INTO test1 (a) VALUES (r.x);
  8. COMMIT;
  9. END LOOP;
  10. END;
  11. /
  12. CALL transaction_test2();

通常,游标会在事务提交时被自动关闭。但是,一个作为循环的组成部分创建的游标会自动被第一个COMMIT或ROLLBACK成一个可保持游标。这意味着该游标在第一个COMMIT或ROLLBACK处会被完全计算出来,而不是逐行被计算。该游标在循环后仍会被自动删除,因此这通常对用户是不可见的。

有非只读命令(UPDATE … RETURNING)驱动的游标循环中不允许有事务命令。

在一个具有异常处理部分的块中同样支持事务的操作,如下面的例子

  1. CREATE PROCEDURE transaction_test3()
  2. AS
  3. BEGIN
  4. INSERT INTO test1 (a) VALUES (1);
  5. COMMIT;
  6. INSERT INTO test1 (a) VALUES (1/0);
  7. COMMIT;
  8. EXCEPTION
  9. WHEN division_by_zero THEN
  10. RAISE NOTICE 'caught division_by_zero';
  11. END;
  12. /
  13. CALL transaction_test3();

上面存储过程执行后将捕获异常,但是第一条插入操作将正常完成。