如何为表创建更改日志?

时间:2017-08-09 09:21:29

标签: mysql debugging changelog

我需要在更改某个字段时创建表行的更改历史记录。所以我想要做的是在表更新上创建一个触发器。当字段txta发生更改时,我希望将整行复制到debug,这是msser_210的克隆版本,最后添加了日期时间列,没有数据。我想在更改时添加NOW(),以便我有时间戳。这是我尝试过的:

DELIMITER $$
CREATE TRIGGER history_trigger
BEFORE UPDATE ON msser_210
    FOR EACH ROW
        BEGIN
        IF OLD.txta != NEW.txta
        THEN
            INSERT INTO `debug_history` (`idpm`,`posn`,`prnb`,`doid`,`ofcr`,`pidm`,`hitm`,`sitm`,`item`,`dsca`,`igid`,`kitm`,`leng`,`widt`,`hght`,`thik`,`radi`,`quas`,`wght`,`effc`,`colr`,`bdat`,`edat`,`back`,`cuid`,`intb`,`aggr`,`unqu`,`oqua`,`unsq`,`stoc`,`allo`,`hall`,`tqan`,`bqan`,`pkey`,`pric`,`cvqs`,`unsp`,`disc`,`dart`,`ksid`,`anhg`,`txta`,`txti`,`mndn`, `changedate`) VALUES (OLD.idpm,OLD.posn,OLD.prnb,OLD.doid,OLD.ofcr,OLD.pidm,OLD.hitm,OLD.sitm,OLD.item,OLD.dsca,OLD.igid,OLD.kitm,OLD.leng,OLD.widt,OLD.hght,OLD.thik,OLD.radi,OLD.quas,OLD.wght,OLD.effc,OLD.colr,OLD.bdat,OLD.edat,OLD.back,OLD.cuid,OLD.intb,OLD.aggr,OLD.unqu,OLD.oqua,OLD.unsq,OLD.stoc,OLD.allo,OLD.hall,OLD.tqan,OLD.bqan,OLD.pkey,OLD.pric,OLD.cvqs,OLD.unsp,OLD.disc,OLD.dart,OLD.ksid,OLD.anhg,OLD.txta,OLD.txti, OLD.mndn, NOW());
    END IF;
END;
$$

为什么我要这样做是因为我们(可能)有一个带有错误的php脚本,该错误将相同的文本字符串写入数据库的每个字段但我们不知道何时或为什么它不会发生在哪个脚本中确实。是否有更优雅的解决方案?

更新:我在phpMyAdmin中找到了“跟踪更改”的选项,但显然它没有跟踪我们的程序php发出的UPDATE查询,来自PHP的DROPCREATE TABLE语句虽然被跟踪了。如果我通过phpMyAdmin发出UPDATE,则会对其进行跟踪。长话短说我用触发器回到原来的计划。

UPDATE2:自己找到答案

2 个答案:

答案 0 :(得分:1)

更新:根据OP的评论,显然上下文非常具体。无法访问(或能够反馈和指导开发团队代码)代码的基础架构团队需要一种机制来记录生产数据库中的表更改。

有关使用触发器的警告

触发器调试起来可能很棘手,尤其是因为它们是透明的,对于看到你的代码的人来说,触发器在幕后执行某些操作时,这一点从未显而易见。 (我从经验中说。)它们还可能导致replicated,多主机和群集安装上的问题。 (同样,我从经验中说。)另外,如果由于某些无关的原因(例如他们写入的表被破坏)而失败,那么整个事务可能/将会失败(InnoDB) - 这可能不是你想要什么。 (特别是非必要的"调试"功能。)

否则,触发器是一个非常有效的工具。 在您的具体情况下,可能是您可以选择的最佳选择。

您还有其他几种选择,其中两个我要强调:

存储过程作为数据的访问层

如果您非常以数据为中心并且您已经在数据库中拥有业务逻辑 - (一个激烈争论的主题,我不是在这里争论您应该或不应该在数据库中拥有业务逻辑)然后通过存储过程读取和写入数据库具有明显的优势。

任何事务绑定逻辑都可以插入到这些存储过程中,这样事务上不安全的调用者(PHP,这是一个常见示例)只需要调用1个查询({ {1}})和事务安全可以由数据库强制执行。

临时调试逻辑可以添加到这些存储过程中,并通过设置表,会话变量,最终参数中的标志启用/禁用,无论您喜欢什么。

数据抽象层/库

类似的原则。为您的客户找到一个数据抽象层(假设您有权改变它的内部)。对于PHP或.NET Web应用程序,有几个流行的选择,所有这些选项都允许您覆盖(通过代码继承扩展)保存/删除操作以执行您想要的任何其他操作 - 与存储过程完全相同(但使用逻辑)维护在客户端的模型内。)

如果您想要一个特定示例,您需要向我们提供有关您正在使用的堆栈/语言/框架的更多信息

使用这两个选项,请确保正确处理错误情况。

答案 1 :(得分:0)

debug_history是从原始表中通过pypMyAdmin克隆的。它手动附加了一个额外的更改列。

ALTER TABLE debug_history ADD COLUMN changedate DATETIME DEFAULT NULL;

我决定因为没有别的方法可以自己输入所有的名字。因为我很懒,所以我得到了一个最近的SQL转储,从用于重建INSERT INTO的文件中复制了msser_210 - 语句并更改了值。

我添加了一个带有自动增量行的额外行,删除了主键并将新主键设置为新行。

ALTER TABLE debug_history DROP PRIMARY KEY;
ALTER TABLE debug_history ADD COLUMN changenumber INT NOT NULL PRIMARY KEY AUTO_INCREMENT;

我现在有一个工作的更改日志,在txta字段的更改时触发(请参阅原始格式的触发器问题)。我将txta中的debug_history列重命名为txta_old并创建了新列txta_new

ALTER TABLE debug_history CHANGE txta txta_old TEXT NOT NULL $$
ALTER TABLE debug_history ADD COLUMN txta_new TEXT NOT NULL AFTER txta_old $$

之后我不得不修改触发器,因为我手动必须复制所有名称..

DROP TRIGGER history_trigger
DELIMITER $$
CREATE TRIGGER history_trigger
BEFORE UPDATE ON msser_210
    FOR EACH ROW
        BEGIN
        IF OLD.txta != NEW.txta
        THEN
            INSERT INTO `debug_history` (`idpm`,`posn`,`prnb`,`doid`,`ofcr`,`pidm`,`hitm`,`sitm`,`item`,`dsca`,`igid`,`kitm`,`leng`,`widt`,`hght`,`thik`,`radi`,`quas`,`wght`,`effc`,`colr`,`bdat`,`edat`,`back`,`cuid`,`intb`,`aggr`,`unqu`,`oqua`,`unsq`,`stoc`,`allo`,`hall`,`tqan`,`bqan`,`pkey`,`pric`,`cvqs`,`unsp`,`disc`,`dart`,`ksid`,`anhg`,`txta_old`,`txta_new`,`txti`,`mndn`, `changedate`) VALUES (OLD.idpm,OLD.posn,OLD.prnb,OLD.doid,OLD.ofcr,OLD.pidm,OLD.hitm,OLD.sitm,OLD.item,OLD.dsca,OLD.igid,OLD.kitm,OLD.leng,OLD.widt,OLD.hght,OLD.thik,OLD.radi,OLD.quas,OLD.wght,OLD.effc,OLD.colr,OLD.bdat,OLD.edat,OLD.back,OLD.cuid,OLD.intb,OLD.aggr,OLD.unqu,OLD.oqua,OLD.unsq,OLD.stoc,OLD.allo,OLD.hall,OLD.tqan,OLD.bqan,OLD.pkey,OLD.pric,OLD.cvqs,OLD.unsp,OLD.disc,OLD.dart,OLD.ksid,OLD.anhg,OLD.txta,NEW.txta,OLD.txti, OLD.mndn, NOW());
        END IF;
    END;
$$