触发器是Oracle,SQL Server和PostgreSQL等所有整体式SQL系统都支持多年的基本功能。从简单的审核日志记录到高级任务(如更新联合集群中的远程数据库),它们在各种情况下都非常有用。在此博客中,我们将查看Yugabyte DB中INSERT,UPDATE和INSTEAD OF触发器的示例。
什么是Yugabyte DB?它是一个开放源代码,高性能,分布式SQL数据库,该数据库基于Google Spanner的可扩展性和容错设计而构建。Yugabyte的SQL API(YSQL)和驱动程序与PostgreSQL有线协议兼容。
按照我们快速入门中的说明,使用Yugabyte DB本地集群启动和运行很简单。
什么是数据库触发器?
触发器是在满足某些条件或发生用户指定的事件时自动执行的功能。在触发器内执行的动作可以是任何东西,从将数据插入数据库,更新和删除数据行等等。
触发器通常绑定到数据库表,并在表创建时创建。简而言之,触发器的行为类似于C / C ++中的IF条件,其中,如果上述条件为true,则并且只有这样,条件内部的指令才会被执行。
为什么要使用触发器?
假设我们有一个雇员表,其中包含雇员和薪水详细信息。在这种简单的情况下,触发器在自动执行冗余任务(例如在员工的个人详细信息或薪水得到更新时更新审核日志)方面很有用。
在这种情况下,手动更新日志记录表并使用之前和之后的值填充它会导致输入错误和潜在的恶意操作。触发器可用于自动执行此任务,如果更新频繁发生且必须立即执行审核日志记录而又没有篡改的机会,则这将是非常有益的。
示例:INSERT和UPDATE触发器
插入和更新触发器的工作与名称一样。只要在表上发生INSERT或UPDATE,就会触发该触发器。
在下面的示例中,我们将创建两个表:employee和trigger_logs。然后,当将新条目添加到employees表中或特定雇员的薪水状态更改时,我们将创建两个触发器来更新trigger_logs表。
首先,让我们创建employees和trigger_logs表:
CREATE TABLE employees ( id INT PRIMARY KEY NOT NULL, NAME TEXT NOT NULL, age INT NOT NULL, address CHAR(50), salary REAL, salary_status TEXT NOT NULL ); CREATE TABLE trigger_logs ( PRIMARY KEY (emp_id, entry_timestamp), emp_id INT NOT NULL, entry_timestamp TEXT NOT NULL, salary_status TEXT NOT NULL );复制
接下来,让我们创建日志记录功能:
CREATE OR REPLACE FUNCTION triggerlogfunc() returns TRIGGER AS $example_table$ BEGIN INSERT INTO trigger_logs ( emp_id, entry_timestamp, salary_status ) VALUES ( new.id, CURRENT_TIMESTAMP, new.salary_status ); RETURN new; END; $example_table$ language plpgsql;复制
现在,让我们创建两个触发器。一种在employees表中发生INSERT时创建审核跟踪,另一种在表中的数据更新时创建审核跟踪。
CREATE TRIGGER example_trigger after INSERT ON employees FOR each row EXECUTE PROCEDURE triggerlogfunc(); CREATE TRIGGER example_trigger1 after UPDATE OF salary_status ON employees FOR each row EXECUTE PROCEDURE triggerlogfunc();复制
接下来,让我们在employee表中插入一个。
INSERT INTO employees ( id, NAME, age, address, salary, salary_status ) VALUES ( 1, 'Paul', 32, 'California', 20000.00, 'Pending' );复制
然后,当我们从employee表中选择数据时,我们可以看到Paul的雇员详细信息已正确插入。
SELECT * FROM employees;复制
如果我们在trigger_logs表中查看数据,则可以看到与Paul插入表有关的条目。
SELECT * FROM trigger_logs;复制
接下来,我们将更新Paul的记录,并使用下面的UPDATE语句将他的薪水状态从“待处理”设置为“已支付”。
UPDATE employees SET salary_status='Paid' WHERE id=1;复制
让我们验证一下他的薪水状况确实发生了变化。
SELECT * FROM employees;复制
现在,当我们查询trigger_logs表以确保已记录更新时:
示例:INSTEAD OF触发器
INSTEAD OF触发器仅用于视图上的INSERT,UPDATE或DELETE。它们被称为“ INSTEAD OF”触发器,因为数据库“代替”运行触发器语句来执行触发器。让我们看一个简单的例子来说明它们的实际作用。
首先,让我们创建一个简单的视图,其中包含ID介于1到10之间的10名雇员,其中Paul是其成员。
CREATE VIEW ten_employees AS SELECT * FROM employees WHERE id BETWEEN 1 AND 10; SELECT * FROM ten_employees;复制
现在,让我们创建一个禁止更新员工工资的函数。
CREATE FUNCTION triggerfunc2() returns TRIGGER language plpgsql SET search_path TO PUBLIC AS $ BEGIN NEW.salary = OLD.salary; return NEW; end; $;复制
接下来,创建INSTEAD OF触发器,当有人尝试更新属于ten_employees视图的雇员的工资时将调用该触发器。
CREATE TRIGGER trigger2 instead OF UPDATE ON ten_employees FOR each row EXECUTE PROCEDURE triggerfunc2();复制
最后,让我们将一些数据插入到employees表中,以测试是否可以通过更新视图来更改雇员的薪水。在这种情况下,我们将尝试为保罗提供1亿美元的新薪水。
UPDATE ten_employees SET salary = '100000000' WHERE name = 'Paul'; SELECT * FROM employees;复制
如您所见,视图上的触发器有效地阻止了薪水的变化。
当前不支持的触发器类型
当前不支持以下触发器类型,但是您可以通过这些GitHub问题来跟踪它们:
· 事件触发
· 可延迟约束
· 触发器的引用子句
我们还应该注意,目前没有其他真正分布式的SQL数据库(例如Google Spanner或CockroachDB)支持任何类型的触发器。