在Postgresql中,可以使用trigger procedure创建触发器。这是创建触发器的便捷方法。使用相同的触发器过程,可以创建多个触发器并将其应用于多个不同的表。我想知道是否有任何与它等效的MySQL。我受到这个博客post的启发,它为数据库审计创建了一个通用触发器。我的计划是使用MySQL实现类似的方法。但是,真的有可能用MySQL创建这样的通用触发器吗?
发布于 2019-02-12 15:15:52
在做了一些研究之后,我了解到在MySQL中没有直接创建泛型触发器的方法。即使是像prepare statement、execute statement这样的动态SQL,在MySQL的触发器内部也是不允许的。
我已经找到了一种动态生成触发器的解决方法。假设我们有一个customer表:
CREATE TABLE customer (
id bigint(20) NOT NULL AUTO_INCREMENT,
created_on datetime DEFAULT NULL,
first_name varchar(100) NOT NULL,
last_name varchar(100) NOT NULL,
PRIMARY KEY (id)
) 修订版信息表:
CREATE TABLE REVINFO (
REV int(11) NOT NULL AUTO_INCREMENT,
REVTSTMP bigint(20) DEFAULT NULL,
PRIMARY KEY (REV)
) 审核表:
CREATE TABLE customer_AUD (
id bigint(20) NOT NULL,
REV int(11) NOT NULL,
REVTYPE tinyint(4) DEFAULT NULL,
created_on datetime DEFAULT NULL,
first_name varchar(100) DEFAULT NULL,
last_name varchar(100) DEFAULT NULL,
PRIMARY KEY (id, REV),
KEY FK_REV (REV)
) 现在,我们将创建一个过程,该过程将接受一个表名并为表的create audit related生成SQL。
DROP PROCEDURE IF EXISTS `proc_trigger_generator`;
DELIMITER $$
CREATE PROCEDURE `proc_trigger_generator` (IN tableName VARCHAR(255))
BEGIN
DECLARE triggerSQL TEXT DEFAULT "";
DECLARE cols TEXT DEFAULT "";
DECLARE col_values TEXT DEFAULT "";
DECLARE insert_query TEXT DEFAULT "";
DECLARE colName TEXT DEFAULT "";
DECLARE done INT DEFAULT FALSE;
DECLARE cursorDS CURSOR FOR SELECT column_name FROM information_schema.columns cols
WHERE cols.table_name = CONCAT(tableName, '_AUD')
and (column_name != 'REV' && column_name != 'REVTYPE');
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
SET triggerSQL = 'DELIMITER ;; \n\n';
SET triggerSQL = CONCAT(triggerSQL, 'drop trigger if exists tr_', tableName, '_update_audit;; \n\n');
SET triggerSQL = CONCAT(triggerSQL, 'create trigger tr_', tableName, '_update_audit \n');
SET triggerSQL = CONCAT(triggerSQL, 'after update \n');
SET triggerSQL = CONCAT(triggerSQL, '\t on ', tableName, '\n');
SET triggerSQL = CONCAT(triggerSQL, 'for each row \n');
SET triggerSQL = CONCAT(triggerSQL, 'begin \n');
SET triggerSQL = CONCAT(triggerSQL, '\t DECLARE tmpInt INT; \n');
SET triggerSQL = CONCAT(triggerSQL, '\t SELECT COALESCE(MAX(REV), 0) FROM REVINFO into tmpInt; \n\n');
SET triggerSQL = CONCAT(triggerSQL, '\t INSERT INTO REVINFO (REV, REVTSTMP) VALUES (tmpInt+1, CURRENT_TIMESTAMP()); \n\n');
SET insert_query = CONCAT(insert_query, 'INSERT INTO ', CONCAT(tableName, '_AUD'), ' (');
OPEN cursorDS;
ds_loop: LOOP
FETCH cursorDS INTO colName;
IF done THEN
LEAVE ds_loop;
END IF;
SET cols = CONCAT(cols, colName, ', ');
SET col_values = CONCAT(col_values, 'new.', colName, ', ');
END LOOP;
SET insert_query = CONCAT(insert_query, cols, 'REV, REVTYPE) VALUES \n');
SET insert_query = CONCAT(insert_query, '\t\t(', col_values, 'tmpInt+1, 1', ');');
CLOSE cursorDS;
SET triggerSQL = CONCAT(triggerSQL, '\t ',insert_query, ' \n\n');
SET triggerSQL = CONCAT(triggerSQL, 'end;; \n\n');
SET triggerSQL = CONCAT(triggerSQL, 'DELIMITER ; \n\n');
SELECT triggerSQL;
END $$
DELIMITER ;
call proc_trigger_generator('customer');使用customer表名调用该过程将为所需的触发器生成SQL:
DELIMITER ;;
drop trigger if exists tr_customer_update_audit;;
create trigger tr_customer_update_audit
after update
on customer
for each row
begin
DECLARE tmpInt INT;
SELECT COALESCE(MAX(REV), 0) FROM REVINFO into tmpInt;
INSERT INTO REVINFO (REV, REVTSTMP) VALUES (tmpInt+1, CURRENT_TIMESTAMP());
INSERT INTO customer_AUD (id, created_on, first_name, last_name, REV, REVTYPE) VALUES
(new.id, new.created_on, new.first_name, new.last_name, tmpInt+1, 1);
end;;
DELIMITER ; 上面的触发器应该对customer表执行审计任务。既然我们希望应用与审计相关的任务,那么触发器生成器过程可以应用于任何其他表。
https://stackoverflow.com/questions/54568298
复制相似问题