Mysql 如何为表创建变更日志?
当某个字段发生更改时,我需要创建表行的更改历史记录。所以我想做的是在表更新时创建一个触发器。当字段Mysql 如何为表创建变更日志?,mysql,debugging,changelog,Mysql,Debugging,Changelog,当某个字段发生更改时,我需要创建表行的更改历史记录。所以我想做的是在表更新时创建一个触发器。当字段txta更改时,我希望整行复制到debug,这是msser_210的克隆版本,末尾添加了一列datetime,没有数据。我想在更改时添加NOW(),这样我就有了时间戳。这就是我迄今为止所尝试的: DELIMITER $$ CREATE TRIGGER history_trigger BEFORE UPDATE ON msser_210 FOR EACH ROW BEGIN
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;
$$
我之所以想这样做,是因为我们有一个php脚本(可能)有一个bug,它将相同的文本字符串写入数据库的每个字段,但我们不知道它发生的时间或原因,也不知道它是哪个脚本。有没有更优雅的解决方案
更新:我在phpMyAdmin中找到了“跟踪更改”的选项,但显然它没有跟踪我们的程序php发出的UPDATE
查询,DROP
和CREATE TABLE
语句。如果我通过phpMyAdmin发布一个更新
,它会被跟踪。长话短说,我带着扳机回到了原来的计划
更新2:我自己找到了答案更新:根据OP的评论,显然上下文非常具体。如果基础架构团队无法访问(或无法反馈和指导开发团队的)代码,则需要一种机制来记录生产数据库中的表更改 关于使用触发器的警告: 触发器可能很难调试,尤其是因为它们是透明的,而且对于刚看过您的代码的人来说,触发器在幕后执行某些操作从来都不明显。(我是根据经验说的。)它们还可能导致多主机和群集安装出现问题。(同样,我是根据经验说的。)此外,如果它们由于一些不相关的原因(例如,它们写入的表被破坏)而失败,那么整个事务可以/将失败(InnoDB)——这可能不是您想要的。(尤其是非必要的“调试”功能。) 否则,触发器是一个非常有效的工具在您的特定场景中,可能是您可用的最佳选择。 您还可以选择其他几个选项,我将重点介绍其中两个选项: 存储过程作为数据访问层 如果您非常以数据为中心,并且在数据库中已经有了业务逻辑(这是一个备受争议的话题,我不是在这里争论您应该或者不应该在数据库中有业务逻辑),那么通过存储过程对数据库进行读写具有明显的优势 任何事务性绑定逻辑都可以插入到这些存储过程中,这样,事务性不安全调用方(PHP,是一个常见的示例)只需要调用一个查询(
call sp_insert_tablename(123,'abc')
),数据库就可以强制执行事务性安全
可以将临时调试逻辑添加到这些存储过程中,并通过设置表中的标志、会话变量、最终参数等启用/禁用临时调试逻辑
数据抽象层/库
类似的原则。为您的客户机找到一个数据抽象层(假设您有权更改其内部结构)。对于PHP或.NET web应用程序,有几种流行的选择,所有这些选择都允许您覆盖(通过代码继承扩展)保存/删除操作,以执行您想要的任何其他操作-与存储过程完全相同(但在客户机中的模型内维护逻辑)
如果你想要一个具体的例子,你需要给我们更多关于你使用的堆栈/语言/框架的信息
使用这两个选项,请确保正确处理错误情况。调试历史记录是通过pypMyAdmin从原始表中克隆的。它手动追加了一个额外的changedate列
ALTER TABLE debug_history ADD COLUMN changedate DATETIME DEFAULT NULL;
我决定这样做是因为没有其他办法,我必须自己输入所有的名字。因为我懒惰,我得到了一个最近的SQL转储,从用于重建msser\u 210
的文件中复制了一个INSERT-INTO
-语句,并更改了值
我添加了一个带有自动增量行的额外行,删除了主键,并将新主键设置为新行
ALTER TABLE debug_history DROP PRIMARY KEY;
ALTER TABLE debug_history ADD COLUMN changenumber INT NOT NULL PRIMARY KEY AUTO_INCREMENT;
我现在有一个工作变更日志,在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;
$$
Tbh的程序是一个失败的事业,我不是它的开发人员,我不能代码php。我是服务器系统管理员,我被告知将所有写入给定数据库的内容都记录下来,这样开发人员就可以调试(甚至没有单元测试等),这样做很好,但我对此无能为力。这是绝对好的。然后我建议我的答案仍然能回答你的问题——“否则,触发器是一个非常有效的工具。”坚持你提出的解决方案,那就好了。我对触发器的体验与你所处的场景完全相同——把触发器放在那里的人被迫这么做。作为一个更广泛话题的一部分,如果我处在你的位置,我会举手(你是否有正式的基础设施接口开发流程,比如devops?)并说“我被迫这么做,这很好,但它会咬到我们,我希望记录在案”。我试过了,但是新表中的列数不同,因为我为changedate添加了一列,并希望设置它。这是跨表复制数据时的常见问题。您可以通过显式地命名字段的子集来限制复制的字段,自动地这样做(如您的示例中所示)将