2017-08-09 83 views
2

当某个字段发生更改时,我需要创建表行的更改历史记录。所以我想要做的是在表更新上创建一个触发器。当字段txta发生变化时,我希望整行被复制到debug,这是msser_210的一个克隆版本,最后添加了datetime的列,而没有数据。我想在更改上添加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; 
$$ 

为什么我要做到这一点是因为我们有(可能)与写入相同的文本字符串到数据库中的每一个领域,而是一个bug PHP脚本我们不知道什么时候或为什么它不会发生它的脚本。有没有更优雅的解决方案?

更新:我发现选项“修订”在phpMyAdmin,但显然它不会跟踪我们的节目的PHP发行UPDATE查询,从PHP的DROPCREATE TABLE语句虽然跟踪。如果我通过phpMyAdmin发出UPDATE,它会被跟踪。长话短说,我回到原来的计划中。

UPDATE2:找到了答案了自己

回答

0

debug_history是通过pypMyAdmin从原始表克隆的。它手动添加了附加的更改列。

ALTER TABLE debug_history ADD COLUMN changedate DATETIME DEFAULT NULL; 

我决定,因为没有其他办法,我必须自己输入所有名称。因为我很懒,所以我得到了一个最近的SQL转储,从用来重建msser_210的文件中复制了INSERT INTO-语句并更改了这些值。

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

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

我现在有一个工作的changelog,引发了关于在txta场变化(请参阅与原来的格式触发的问题)。我将debug_history中的txta列更名为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; 
$$ 
1

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

警告有关使用触发器

触发器可能会非常棘手的调试,这不仅是因为他们是透明的,它是一个新的人从来没有明显的看你的代码,触发被执行后面的一些动作场景。 (我根据经验说话)。它们也可能导致replicated,多主站和群集安装中的问题。 (同样,我是从经验讲的。)另外,如果由于某种不相关的原因而失败(例如,他们写入的表被破坏),整个事务可能会失败(InnoDB) - 这可能不是您想要的。 (尤其是非必要的“调试”功能。)

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

有提供给您多种其它选项,其中有两个我要强调:

存储过程作为接入层到数据

如果你非常以数据为中心,你已经有了数据库中的业务逻辑 - (一个激烈争论的话题,我不是在争论你应该或不应该在数据库中有业务逻辑),那么通过存储过程读取和写入数据库具有明显的优势。

不限事务捆绑逻辑可以被插入,使得事务不安全呼叫者(PHP,作为一个常见的例子)只需要调用1个查询(call sp_insert_tablename(123, 'abc'))和事务安全可由强制执行这些存储的过程数据库。

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

数据抽象层/库

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

如果你想有一个具体的例子,你需要给我们什么堆/语言/框架()你正在使用

与这两个选项的详细信息,请务必妥善处理错误情况。

+1

TBH程序是一个失败的事业,我不是它的开发者,我不能代码PHP。我是服务器SysAdmin,我被告知将所有写入给定数据库的日志都记录下来,所以开发人员可以调试(甚至没有单元测试等),这样很好,但几乎没有,我真的可以做到这一点 – siryx

+0

这绝对没问题。那么我会建议我的答案仍然回答你的问题 - “否则,触发器是一个完全有效的工具。”坚持你提出的解决方案,那会很好。我与触发器的经验是由于你的情况完全相同 - 把他们放在那里的人被迫去做。作为更广泛的话题的一部分,如果我处于你的位置,我会举手(你是否有正式的基础设施流程来接口开发人员,比如devops?),并说:“我被迫做这个,没问题,但它会咬我们,我想要记录下来“。 – wally

+0

我尝试过了,但新表中的列数量不同,因为我为changedate添加了一列,并且想要将其设置为 – siryx