【问题标题】:Mysql Log triggerMysql 日志触发器
【发布时间】:2015-06-16 09:32:10
【问题描述】:

我想知道是否有可能将多个表的更改记录到一个日志表中。每列都应该记录到自己的行中。

这些表并不相同,但每个都有:

  • UID(PK),
  • 已创建(日期时间),
  • 修改(日期时间),
  • MODIFIED_BY (id)

有些表格有额外的列,例如:

  • Data_Table_1 有附加列:NAME、ACTIVE、ORDER
  • Data_Table_2 有附加列:DATABASE、ACTIVE、POSITION_NAME

Log_Table 应该有以下列:

  • LOG_UID - (PK)
  • EDITED - 现在填写的日期时间
  • TABLE-由已更改的表名填充(Data_Table_1,Data_Table_2)
  • COLUMN- 由相应列填充,已更改
  • USER - 由 MODIFIED_BY 填写
  • VALUE - 由查询中已更改的每一列的值填充
  • 类型-插入/更新/删除
  • LOG_GROUP_UID - 哪些行对应同一个查询
  • LAST_LOG_GROUP_UID -(不是真的必要)这是最后一个查询
  • LAST_LOG_UID -(不是必需的)这是该表中的前一个对应行

我只想要一个日志表,它记录所有表(具有或不具有相同列)的所有初始值、更新和删除,除了它自己。它应该发生在 mysql 中,因此 phpMyAdmin、php、python... 中的每一次更改都会被记录并

这样的事情可能吗?

【问题讨论】:

    标签: mysql logging triggers


    【解决方案1】:

    您似乎需要审核数据更改,而不是能够查看给定日期的数据状态,因为根据您的解决方案重建数据状态将非常复杂(如果我错了,请纠正在这个假设中)。我认为这个想法不可行,因为即使对于非常小的数据库,您的日志表也会很大,因此很难正确管理。

    审计数据更改的轻松解决方案是为您要跟踪的每个表创建一个历史记录表。该表将为在每一行上执行的每个插入、更新和删除查询都有一个条目。历史表的结构将与其跟踪的表相同,除了三个额外的列,一个用于存储发生的操作的列,一个用于存储序列号的列和一个用于保存发生时间戳的列。

    以下查询产生创建这些审计表所需的 SQL,但它仅在以下情况下有效:

    1. 您的表不以_ 开头(因为审计表将 做);
    2. 您的表有一个非复合主键;
    3. 您的表没有名为 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 将根据原始表的定义创建一个空表,包括任何列属性和索引,但忽略其他所有内容(如数据、外键等)。原始表约束正在验证数据完整性,因此在审计表中使用外键并没有任何好处。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-17
      • 2017-02-28
      • 2020-02-11
      • 2011-05-11
      • 2021-03-09
      相关资源
      最近更新 更多