分析触发器正在处理的记录:

  • 对于一个 INSERT 触发器,OLD 记录没有值,NEW 记录包含新增的值。
  • 对于一个 UPDATE 触发器,OLD 记录包含更新前的值, NEW 记录包含更新后的值。
  • 对于一个 DELETE 触发器,OLD 记录包含删除前的值,NEW 记录没有值。

要引用一个伪记录,需要在名称前加一个冒号“ :OLD ” 或“ :NEW ”。

  • INSERTING:表示本次执行是由 INSERT 语句触发。
  • UPDATING:表示本次执行是由 UPDATE 语句触发。
  • UPDATING(‘column_name’):表示本次执行由更新指定列的 UPDATE 语句触发。
  • DELETING: 表示本次执行由 DELETE 语句触发。

以下示例创建了一个表 account ,其 ID 要求是自增的,可以使用序列 seq_account.nextval 值填充这个列。通常可以要求客户端所有应用去显式插入这个值,另外一种方法就是利用表的行级 BEFORE INSERT 触发器实现。

以下示例演示如何用触发器实现对业务表的关键数据变化的审计,将表的关键字段变更记录到一个日志表中。

  1. , name varchar2(50) NOT NULL UNIQUE
  2. , value number NOT NULL
  3. , gmt_create date DEFAULT sysdate NOT NULL
  4. , gmt_modified date DEFAULT sysdate NOT NULL );
  5. CREATE TABLE account_log(id number NOT NULL PRIMARY KEY
  6. , acc_id number NOT NULL
  7. , acc_name varchar2(50) NOT NULL
  8. , old_value number NULL
  9. , new_value number NULL
  10. , gmt_create date DEFAULT sysdate NOT NULL );
  11. CREATE SEQUENCE seq_account_log START WITH 1 INCREMENT BY 1 nocycle ;
  12. CREATE SEQUENCE seq_account START WITH 1 INCREMENT BY 1 nocycle;
  13. delimiter /
  14. CREATE OR REPLACE TRIGGER trg_after_dml_account
  15. AFTER INSERT OR UPDATE OR DELETE
  16. ON account
  17. FOR EACH ROW
  18. DECLARE
  19. acc_name account.name%TYPE ;
  20. old_value account.value%TYPE;
  21. new_value account.value%TYPE;
  22. BEGIN
  23. IF INSERTING THEN
  24. acc_id := :NEW.id;
  25. new_value := :NEW.value;
  26. ELSIF UPDATING THEN
  27. acc_id := :NEW.id;
  28. acc_name := :NEW.name;
  29. new_value := :NEW.value;
  30. old_value := :OLD.value;
  31. ELSIF DELETING THEN
  32. acc_id := :OLD.id;
  33. acc_name := :OLD.name;
  34. old_value := :OLD.value;
  35. ELSE
  36. dbms_output.put_line('This code is not applicable.') ;
  37. END IF ;
  38. INSERT INTO account_log(id, acc_id, acc_name, old_value, new_value)
  39. VALUES(seq_account_log.nextval, acc_id, acc_name, old_value, new_value);
  40. END ;
  41. /
  42. delimiter ;
  43. obclient> INSERT INTO account(id,name, value) VALUES(1,'Jack', 100),(2,'Jim', 200),(3,'Mike', 150);
  44. Query OK, 3 rows affected (0.15 sec)
  45. Records: 3 Duplicates: 0 Warnings: 0
  46. obclient> UPDATE account SET value=value*2, gmt_Modified=sysdate ;
  47. Rows matched: 3 Changed: 3 Warnings: 0
  48. Query OK, 1 row affected (0.00 sec)
  49. obclient> COMMIT;
  50. Query OK, 0 rows affected (0.01 sec)
  51. obclient> SELECT * FROM account;
  52. +----+------+-------+---------------------+---------------------+
  53. | ID | NAME | VALUE | GMT_CREATE | GMT_MODIFIED |
  54. +----+------+-------+---------------------+---------------------+
  55. | 1 | Jack | 200 | 2020-03-11 18:04:55 | 2020-03-11 18:05:00 |
  56. | 3 | Mike | 300 | 2020-03-11 18:04:55 | 2020-03-11 18:05:00 |
  57. +----+------+-------+---------------------+---------------------+
  58. 2 rows in set (0.00 sec)
  59. obclient> SELECT * FROM account_log;
  60. +----+--------+----------+-----------+-----------+---------------------+
  61. | ID | ACC_ID | ACC_NAME | OLD_VALUE | NEW_VALUE | GMT_CREATE |
  62. +----+--------+----------+-----------+-----------+---------------------+
  63. | 1 | 1 | Jack | NULL | 100 | 2020-03-11 18:04:56 |
  64. | 2 | 2 | Jim | NULL | 200 | 2020-03-11 18:04:56 |
  65. | 3 | 3 | Mike | NULL | 150 | 2020-03-11 18:04:56 |
  66. | 4 | 1 | Jack | 100 | 200 | 2020-03-11 18:05:00 |
  67. | 5 | 2 | Jim | 200 | 400 | 2020-03-11 18:05:00 |
  68. | 6 | 3 | Mike | 150 | 300 | 2020-03-11 18:05:00 |
  69. | 7 | 2 | Jim | 400 | NULL | 2020-03-11 18:05:03 |
  70. +----+--------+----------+-----------+-----------+---------------------+
  71. 7 rows in set (0.00 sec)