赞
踩
专栏内容:
在postgresql 中,触发器与SQL标准相比,有一个扩展特性就是可以在视图上创建触发器。
在视图上的触发器类型是’INSTEAD OF`,可以在insert, update, delete事件的before或after进行触发,
本文就来详细分享一下,并通过一个实用的审计数据的案例来展示效果。
下面先来介绍SQL语法,然后通过介绍它的执行过程,了解它的机制原理。
视图触发器的创建语法如下:
CREATE TRIGGER trigger_name
INSTEAD OF [INSERT OR UPDATE OR DELETE]
ON table_name
FOR EACH ROW
EXECUTE FUNCTION trigger_function;
在视图上的触发器,类型只有INSTEAT OF,而且它对应的触发器件有insert,update,delete,此处没有truncate事件。
另外,instead of 触发器也只能定义为行级触发器,这个原因下面会分析。
视图触发器执行的步骤如下
如果视图上没有INSTEAD OF触发器,那么对视图的操作必须被转换为对基础表的操作,是直接操作基础表。
为了信息的安全,一般系统都会有审计这个功能,其中审计日志会把操作记录详细记录下来,会定期时行审计或者出问题时能够帮助回溯。
下面就来分享一个通过触发器实现的审计日志功能,大概设计如下:
CREATE TABLE emp (
empname text PRIMARY KEY,
salary integer
);
CREATE TABLE emp_audit(
operation char(1) NOT NULL,
userid text NOT NULL,
empname text NOT NULL,
salary integer,
stamp timestamp NOT NULL
);
CREATE VIEW emp_view AS
SELECT e.empname,
e.salary,
max(ea.stamp) AS last_updated
FROM emp e
LEFT JOIN emp_audit ea ON ea.empname = e.empname
GROUP BY 1, 2;
CREATE OR REPLACE FUNCTION update_emp_view() RETURNS TRIGGER AS $$ BEGIN IF (TG_OP = 'DELETE') THEN DELETE FROM emp WHERE empname = OLD.empname; IF NOT FOUND THEN RETURN NULL; END IF; OLD.last_updated = now(); INSERT INTO emp_audit VALUES('D', current_user, OLD.*); RETURN OLD; ELSIF (TG_OP = 'UPDATE') THEN UPDATE emp SET salary = NEW.salary WHERE empname = OLD.empname; IF NOT FOUND THEN RETURN NULL; END IF; NEW.last_updated = now(); INSERT INTO emp_audit VALUES('U', current_user, NEW.*); RETURN NEW; ELSIF (TG_OP = 'INSERT') THEN INSERT INTO emp VALUES(NEW.empname, NEW.salary); NEW.last_updated = now(); INSERT INTO emp_audit VALUES('I', current_user, NEW.*); RETURN NEW; END IF; END; $$ LANGUAGE plpgsql;
在视图emp_view上创建instead of类型的触发器,使用上面定义的函数。
CREATE TRIGGER emp_audit
INSTEAD OF INSERT OR UPDATE OR DELETE ON emp_view
FOR EACH ROW EXECUTE FUNCTION update_emp_view();
测试一下审计模块的效果。
员工管理系统中,对于薪资表结构如下:
postgres=> \d emp_view
View "senlleng.emp_view"
Column | Type | Collation | Nullable | Default
--------------+-----------------------------+-----------+----------+---------
empname | text | | |
salary | integer | | |
last_updated | timestamp without time zone | | |
Triggers:
emp_audit INSTEAD OF INSERT OR DELETE OR UPDATE ON emp_view FOR EACH ROW EXECUTE FUNCTION update_emp_view()
有新员工入职,录入新员工的薪资。
postgres=> insert into emp_view values('zhanglei', 10000);
INSERT 0 1
postgres=> insert into emp_view values('wangguo', 8000);
INSERT 0 1
postgres=> select * from emp_audit ;
operation | userid | empname | salary | stamp
-----------+----------+----------+--------+----------------------------
I | senllang | zhanglei | 10000 | 2024-06-06 08:13:05.829596
I | senllang | wangguo | 8000 | 2024-06-06 08:13:24.125127
(2 rows)
有两名新员工入职,可以看到是那个操作员录入的,并且当前录入的时间,信息都可以看到。
当人员调岗时,对应的薪资也会发生变化;
或者人员离职时,需要删除对应的记录。
postgres=> update emp_view set salary = 7500 where empname='wangguo';
UPDATE 1
postgres=> delete from emp_view where empname='zhanglei';
DELETE 1
postgres=> select * from emp_audit ;
operation | userid | empname | salary | stamp
-----------+----------+----------+--------+----------------------------
I | senllang | zhanglei | 10000 | 2024-06-06 08:13:05.829596
I | senllang | wangguo | 8000 | 2024-06-06 08:13:24.125127
U | senllang | wangguo | 7500 | 2024-06-06 08:14:30.737416
D | senllang | zhanglei | 10000 | 2024-06-06 08:14:53.089083
(4 rows)
当然审计表的权限是非常高的,只有在审计系统中才能查看,而且审计数据是不能删除的。
在视图上的instead of 触发器,可以将原本的执行计划重写 替换为触发器执行,这样可以进行更为复杂的动作,这里以审计为例,演示了触发器的效果。
非常感谢大家的支持,在浏览的同时别忘了留下您宝贵的评论,如果觉得值得鼓励,请点赞,收藏,我会更加努力!
作者邮箱:study@senllang.onaliyun.com
如有错误或者疏漏欢迎指出,互相学习。
注:未经同意,不得转载!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。