在更新后在 MySQL 触发器中构建 JSON

alt*_*ser 0 mysql json

如果能够获得一些帮助来在 MySQL 5.6 中实现触发器来记录更新的信息,那就太好了。

\n\n

首先,这是我的数据表和日志表:

\n\n
CREATE TABLE t1\n(id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,\n data1 VARCHAR(255) NOT NULL,\n data2 DECIMAL(5,2) NOT NULL\n);\n\nCREATE TABLE t1_log\n(action VARCHAR(10) NOT NULL,\n timestamp TIMESTAMP NOT NULL,\n id INTEGER NOT NULL,\n data1 VARCHAR(255) NOT NULL,\n data2 DECIMAL(5,2) NOT NULL,\n data1_old VARCHAR(255),\n data2_old DECIMAL(5,2)\n);\n
Run Code Online (Sandbox Code Playgroud)\n\n

这是我的触发器:

\n\n
CREATE TRIGGER after_update_t1 AFTER UPDATE ON t1\n FOR EACH ROW\n BEGIN\n   INSERT INTO t1_log (action,timestamp,id,data1,data2,data1_old,data2_old)\n   VALUES (\'update\',NOW(),NEW.id,NEW.data1,NEW.data2,OLD.data1,OLD.data2);\n END;\n
Run Code Online (Sandbox Code Playgroud)\n\n

这样做没有任何问题。但这个解决方案的缺点是我需要为每个数据表提供一个日志表。 \xc2\xa0 \n因此我考虑是否可能只有一个带有 BLOB 字段的日志表,将更新的字段组合到 JSON 字符串并存储它在这个 BLOB 中。但如何为此定义触发器呢?

\n\n

在伪代码中它看起来像这样:

\n\n
BEGIN\n\xc2\xa0 SET jsonString = "{"\n\xc2\xa0 FOR EACH field in NEW\n\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0 jsonString += field.name + ":" + field.value + ","\n\xc2\xa0 END FOR\n\xc2\xa0 FOR EACH field in OLD\n\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0 jsonString += field.name + ":" + field.value + ","\n\xc2\xa0 END FOR\n\xc2\xa0 jsonString = TRIM(jsonString, ",") + "}"\n\xc2\xa0 INSERT INTO log (action,timestamp,jsondata)\n\xc2\xa0 VALUES (\'update\',NOW(),jsonString)\nEND\n
Run Code Online (Sandbox Code Playgroud)\n

Bil*_*win 5

如果是我并且有此要求,我只会使用现有的审核日志插件之一。例如: https: //www.percona.com/doc/percona-server/LATEST/management/audit_log_plugin.html

如果您无法使用审核日志插件,或者您只想记录自己的 JSON,至少避免通过字符串连接构建 JSON 值。这也太容易出错了吧

相反,请使用函数JSON_OBJECT()。这在 MySQL 5.7 及更高版本中可用。如果您使用的是早期版本的 MySQL 并且想要使用 JSON 数据,则应该升级。

INSERT INTO log SET action = 'update', timestamp = NOW(),
  jsondata = JSON_OBJECT(
    'id', NEW.id,
    'data1', NEW.data1,
    'data2', NEW.data2
  );
Run Code Online (Sandbox Code Playgroud)

我也不建议尝试创建一个可用于任何表的通用触发器。无论如何,您都需要为要记录的每个表定义触发器,因此您应该使用相应表的列自定义触发器。

您可能会想使用 INFORMATION_SCHEMA.COLUMNS 来收集表的列列表,但请记住,每次对基表执行 INSERT 或 UPDATE 操作时,这都会执行查询 INFORMATION_SCHEMA.COLUMNS 的工作。这是大量的查询,并且会导致性能问题。