Mysql 日志触发器
Mysql Log trigger
我想知道是否有可能将多个 Table 的更改记录到一个 Log-Table 中。每列都应记录到自己的行中。
Table 不相同,但每个都有:
- UID(PK),
- 已创建(日期时间),
- 已修改(日期时间),
- MODIFIED_BY (id)
一些 Table 有额外的列,例如:
- Data_Table_1 有附加列:NAME、ACTIVE、ORDER
- Data_Table_2 有附加列:DATABASE、ACTIVE、POSITION_NAME
Log_Table 应该有以下列:
- LOG_UID - (PK)
- 已编辑 - 由现在填充的日期时间
- TABLE- 由 table 已更改的名称填充 (Data_Table_1, Data_Table_2)
- COLUMN- 由相应列填充,已更改
- USER - 由 MODIFIED_BY
填写
- VALUE - 由已更改的查询中每一列的值填充
- 类型- INSERT/UPDATE/DELETE
- LOG_GROUP_UID - 哪些行对应于相同的查询
- LAST_LOG_GROUP_UID -(不是真正必要的)这是
的最后一个查询
- LAST_LOG_UID -(不是真正必要的)这是此 Table
中的前一个对应行
我只想要一个 Log-Table 记录所有 Table 的所有初始值、更新和删除(有或没有相同的列),除了它自己。它应该在 mysql 中发生,因此 phpMyAdmin、php、python... 中的每个更改都会被记录下来,并且
这样的事情有可能吗?
您似乎需要审核数据更改,而不是能够查看给定日期的数据状态,因为根据您的解决方案重建数据状态会非常复杂(如果我是正确的,这个假设是错误的)。我认为这个想法不可行,因为即使对于非常小的数据库,您的日志 table 也会很大,因此很难正确管理。
审核数据更改的一种轻松解决方案是为您要跟踪的每个 table 创建一个历史记录 table。此 table 将为在每一行上执行的每个插入、更新和删除查询创建一个条目。历史 table 的结构将与其跟踪的 table 相同,除了三个额外的列,一个用于存储发生的操作的列,一个用于存储序列号的列和一个用于保存的列发生时间戳。
以下查询会导致创建这些审计 table 所需的 SQL,但它仅在以下情况下有效:
- 您的 table 不以
_
开头(因为审计 table 将
做);
- 您的 table 有一个非复合主键;
- 您的 table 没有名为 Registrated、Action 和
修订。
查询:
SET sql_mode = 'PIPES_AS_CONCAT';
SELECT
'CREATE TABLE __' || table_name || ' LIKE ' || table_name || ';\r\n' ||
'RENAME TABLE __' || table_name || ' TO _' || table_name || ';\r\n' ||
'ALTER TABLE _' || table_name || ' ADD Registrated TIMESTAMP NOT NULL FIRST;\r\n' ||
'ALTER TABLE _' || table_name || ' ADD Action TINYINT UNSIGNED NOT NULL FIRST;\r\n' ||
'ALTER TABLE _' || table_name || ' ADD Revision INT UNSIGNED NOT NULL FIRST;\r\n' ||
'ALTER TABLE _' || table_name || ' MODIFY ' || column_name || ' ' || UPPER(data_type) || IF(is_nullable = 'NO', ' NOT NULL', '') || ';\r\n' ||
'ALTER TABLE _' || table_name || ' DROP PRIMARY KEY;\r\n' ||
'ALTER TABLE _' || table_name || ' MODIFY COLUMN Revision INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY;\r\n' ||
'CREATE TRIGGER i' || table_name || ' AFTER INSERT ON ' || table_name || ' FOR EACH ROW INSERT INTO _' || table_name || ' SELECT NULL, 1, CURRENT_TIMESTAMP, ' || table_name || '.* FROM ' || table_name || ' WHERE ' || table_name || '.' || column_name || ' = NEW.' || column_name || ';\r\n' ||
'CREATE TRIGGER u' || table_name || ' AFTER UPDATE ON ' || table_name || ' FOR EACH ROW INSERT INTO _' || table_name || ' SELECT NULL, 2, CURRENT_TIMESTAMP, ' || table_name || '.* FROM ' || table_name || ' WHERE ' || table_name || '.' || column_name || ' = NEW.' || column_name || ';\r\n' ||
'CREATE TRIGGER d' || table_name || ' BEFORE DELETE ON ' || table_name || ' FOR EACH ROW INSERT INTO _' || table_name || ' SELECT NULL, 3, CURRENT_TIMESTAMP, ' || table_name || '.* FROM ' || table_name || ' WHERE ' || table_name || '.' || column_name || ' = OLD.' || column_name || ';'
FROM information_schema.tables
JOIN information_schema.table_constraints USING (table_schema, table_name)
JOIN information_schema.key_column_usage USING (table_schema, table_name, constraint_name)
JOIN information_schema.columns USING (table_schema, table_name, column_name)
WHERE
information_schema.tables.table_schema = (SELECT DATABASE()) AND
information_schema.table_constraints.constraint_type = 'PRIMARY KEY';
注1:外键是参照完整性工具,不是性能工具。一个好的数据库模型会表现得更好,但外键本身会导致更多的处理发生,而不是更少。 CREATE TABLE LIKE
将根据原始 table 的定义创建一个空 table,包括任何列属性和索引,但忽略其他所有内容(如数据、外键等)。数据完整性由原始 tables 约束进行验证,因此在审计 tables 中使用外键没有任何好处。
我想知道是否有可能将多个 Table 的更改记录到一个 Log-Table 中。每列都应记录到自己的行中。
Table 不相同,但每个都有:
- UID(PK),
- 已创建(日期时间),
- 已修改(日期时间),
- MODIFIED_BY (id)
一些 Table 有额外的列,例如:
- Data_Table_1 有附加列:NAME、ACTIVE、ORDER
- Data_Table_2 有附加列:DATABASE、ACTIVE、POSITION_NAME
Log_Table 应该有以下列:
- LOG_UID - (PK)
- 已编辑 - 由现在填充的日期时间
- TABLE- 由 table 已更改的名称填充 (Data_Table_1, Data_Table_2)
- COLUMN- 由相应列填充,已更改
- USER - 由 MODIFIED_BY 填写
- VALUE - 由已更改的查询中每一列的值填充
- 类型- INSERT/UPDATE/DELETE
- LOG_GROUP_UID - 哪些行对应于相同的查询
- LAST_LOG_GROUP_UID -(不是真正必要的)这是 的最后一个查询
- LAST_LOG_UID -(不是真正必要的)这是此 Table 中的前一个对应行
我只想要一个 Log-Table 记录所有 Table 的所有初始值、更新和删除(有或没有相同的列),除了它自己。它应该在 mysql 中发生,因此 phpMyAdmin、php、python... 中的每个更改都会被记录下来,并且
这样的事情有可能吗?
您似乎需要审核数据更改,而不是能够查看给定日期的数据状态,因为根据您的解决方案重建数据状态会非常复杂(如果我是正确的,这个假设是错误的)。我认为这个想法不可行,因为即使对于非常小的数据库,您的日志 table 也会很大,因此很难正确管理。
审核数据更改的一种轻松解决方案是为您要跟踪的每个 table 创建一个历史记录 table。此 table 将为在每一行上执行的每个插入、更新和删除查询创建一个条目。历史 table 的结构将与其跟踪的 table 相同,除了三个额外的列,一个用于存储发生的操作的列,一个用于存储序列号的列和一个用于保存的列发生时间戳。
以下查询会导致创建这些审计 table 所需的 SQL,但它仅在以下情况下有效:
- 您的 table 不以
_
开头(因为审计 table 将 做); - 您的 table 有一个非复合主键;
- 您的 table 没有名为 Registrated、Action 和 修订。
查询:
SET sql_mode = 'PIPES_AS_CONCAT';
SELECT
'CREATE TABLE __' || table_name || ' LIKE ' || table_name || ';\r\n' ||
'RENAME TABLE __' || table_name || ' TO _' || table_name || ';\r\n' ||
'ALTER TABLE _' || table_name || ' ADD Registrated TIMESTAMP NOT NULL FIRST;\r\n' ||
'ALTER TABLE _' || table_name || ' ADD Action TINYINT UNSIGNED NOT NULL FIRST;\r\n' ||
'ALTER TABLE _' || table_name || ' ADD Revision INT UNSIGNED NOT NULL FIRST;\r\n' ||
'ALTER TABLE _' || table_name || ' MODIFY ' || column_name || ' ' || UPPER(data_type) || IF(is_nullable = 'NO', ' NOT NULL', '') || ';\r\n' ||
'ALTER TABLE _' || table_name || ' DROP PRIMARY KEY;\r\n' ||
'ALTER TABLE _' || table_name || ' MODIFY COLUMN Revision INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY;\r\n' ||
'CREATE TRIGGER i' || table_name || ' AFTER INSERT ON ' || table_name || ' FOR EACH ROW INSERT INTO _' || table_name || ' SELECT NULL, 1, CURRENT_TIMESTAMP, ' || table_name || '.* FROM ' || table_name || ' WHERE ' || table_name || '.' || column_name || ' = NEW.' || column_name || ';\r\n' ||
'CREATE TRIGGER u' || table_name || ' AFTER UPDATE ON ' || table_name || ' FOR EACH ROW INSERT INTO _' || table_name || ' SELECT NULL, 2, CURRENT_TIMESTAMP, ' || table_name || '.* FROM ' || table_name || ' WHERE ' || table_name || '.' || column_name || ' = NEW.' || column_name || ';\r\n' ||
'CREATE TRIGGER d' || table_name || ' BEFORE DELETE ON ' || table_name || ' FOR EACH ROW INSERT INTO _' || table_name || ' SELECT NULL, 3, CURRENT_TIMESTAMP, ' || table_name || '.* FROM ' || table_name || ' WHERE ' || table_name || '.' || column_name || ' = OLD.' || column_name || ';'
FROM information_schema.tables
JOIN information_schema.table_constraints USING (table_schema, table_name)
JOIN information_schema.key_column_usage USING (table_schema, table_name, constraint_name)
JOIN information_schema.columns USING (table_schema, table_name, column_name)
WHERE
information_schema.tables.table_schema = (SELECT DATABASE()) AND
information_schema.table_constraints.constraint_type = 'PRIMARY KEY';
注1:外键是参照完整性工具,不是性能工具。一个好的数据库模型会表现得更好,但外键本身会导致更多的处理发生,而不是更少。 CREATE TABLE LIKE
将根据原始 table 的定义创建一个空 table,包括任何列属性和索引,但忽略其他所有内容(如数据、外键等)。数据完整性由原始 tables 约束进行验证,因此在审计 tables 中使用外键没有任何好处。