MySQL触发器还是PHP数据审计?
MySQL Trigger or PHP for data audit?
我希望在我的应用程序中保留 table 的每一次更新的历史记录。我正在使用 Laravel,我知道有一些软件包可以帮助我,但我正在寻找干净快速的东西。
我有两个选择:
- MySQL 触发器
- 通过PHP代码
我的第一个问题是,哪个更快?
我的第二个问题是:
我应该使用这样的架构并将我所有的 table 存储到其中吗:
CREATE TABLE revisions (
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`revisionable_type` VARCHAR(255) NOT NULL COLLATE 'utf8_unicode_ci',
`revisionable_id` INT(11) NOT NULL,
`user_id` INT(11) NULL DEFAULT NULL,
`key` VARCHAR(255) NOT NULL COLLATE 'utf8_unicode_ci',
`old_value` TEXT NULL COLLATE 'utf8_unicode_ci',
`new_value` TEXT NULL COLLATE 'utf8_unicode_ci',
`created_at` TIMESTAMP NULL DEFAULT NULL,
`updated_at` TIMESTAMP NULL DEFAULT NULL
)
或者我应该为每个 table 重新创建一个 "duplicate",例如 user_history,然后在各自的列中添加历史记录
Users: id, name, surname ...
Users_history: id, user_id, name, surname ...
- 对这两种解决方案进行计时,您会发现哪一种更适合您。无法判断在您的应用程序和环境中哪个会更快。
这是一项设计决定,因此完全取决于您和您的要求。您需要考虑以下事项:
如果用户更改了交易中的记录,则所有受影响的字段将由同一用户同时更改。使用您建议的结构,所有这些更改都需要一个单独的条目。
使用您建议的结构,更难确定某条记录在给定时间点的样子,因为您基本上必须重播该记录插入后的所有更改。
在专业方面,所有更改都存储在一个 table 中,即使您更改数据库架构,也不必更改日志记录的结构。
您还必须考虑是要记录所有 table 的更改还是只记录部分选定的更改。
如果正在记录的 table 引用其他 table,您还需要考虑如何记录。例如,如果你想记录交易,那么你可能有一个交易类型字段和一个单独的交易类型 table 列出详细描述,也许还有关于每个交易类型的其他信息。如果一个交易类型不再被使用,那么它可以从交易类型中移除table或者它的参数可能会改变。
鉴于此架构:
CREATE TABLE contacts (
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`first_name` VARCHAR(255) NOT NULL COLLATE 'utf8_unicode_ci',
`last_name` VARCHAR(255) NOT NULL COLLATE 'utf8_unicode_ci',
`updated_by` VARCHAR(255) NOT NULL COLLATE 'utf8_unicode_ci',
`updated_at` TIMESTAMP NULL DEFAULT NULL
)
我也会创建这个架构:
CREATE TABLE contacts_audit (
`id` INT(10) UNSIGNED NOT NULL,
`first_name` VARCHAR(255) NOT NULL COLLATE 'utf8_unicode_ci',
`last_name` VARCHAR(255) NOT NULL COLLATE 'utf8_unicode_ci',
`updated_by` VARCHAR(255) NOT NULL COLLATE 'utf8_unicode_ci',
`updated_at` TIMESTAMP NULL DEFAULT NULL,
`action` varchar(255) NOT NULL COLLATE 'utf8_unicode_ci'
)
然后使用这些触发器(希望我的触发器语法不会太生疏):
CREATE TRIGGER contacts_audit_insert
AFTER INSERT
ON users FOR EACH ROW
BEGIN
INSERT INTO contacts_audit (id, first_name, last_name, updated_by, updated_at, action) values (NEW.id, NEW.first_name, NEW.last_name, NEW.updated_by, NEW.updated_at, 'insert');
END;
CREATE TRIGGER contacts_audit_update
AFTER UPDATE
ON users FOR EACH ROW
BEGIN
INSERT INTO contacts_audit (id, first_name, last_name, updated_by, updated_at, action) values (NEW.id, NEW.first_name, NEW.last_name, NEW.updated_by, NEW.updated_at, 'update');
END;
CREATE TRIGGER contacts_audit_delete
BEFORE DELETE
ON users FOR EACH ROW
BEGIN
INSERT INTO contacts_audit (id, first_name, last_name, updated_by, updated_at, action) values (OLD.id, OLD.first_name, OLD.last_name, OLD.updated_by, OLD.updated_at, 'delete');
END;
潜在缺点
如果您使用 MySQL username/password 进行数据库访问并根据 MySQL 中的 users
table 对您的用户进行身份验证,那么在执行任何操作之前删除,您需要在 PHP 内执行更新,然后执行删除,以便您可以捕获谁删除了您的记录。
但是,如果您使用 MySQL 对所有用户进行身份验证,那么您可以在触发器中使用:注意 USER()
的使用
INSERT INTO contacts_audit (id, first_name, last_name, updated_by, updated_at, action) values (NEW.id, NEW.first_name, NEW.last_name, USER(), NEW.updated_at, 'insert');
我希望在我的应用程序中保留 table 的每一次更新的历史记录。我正在使用 Laravel,我知道有一些软件包可以帮助我,但我正在寻找干净快速的东西。
我有两个选择:
- MySQL 触发器
- 通过PHP代码
我的第一个问题是,哪个更快?
我的第二个问题是: 我应该使用这样的架构并将我所有的 table 存储到其中吗:
CREATE TABLE revisions (
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`revisionable_type` VARCHAR(255) NOT NULL COLLATE 'utf8_unicode_ci',
`revisionable_id` INT(11) NOT NULL,
`user_id` INT(11) NULL DEFAULT NULL,
`key` VARCHAR(255) NOT NULL COLLATE 'utf8_unicode_ci',
`old_value` TEXT NULL COLLATE 'utf8_unicode_ci',
`new_value` TEXT NULL COLLATE 'utf8_unicode_ci',
`created_at` TIMESTAMP NULL DEFAULT NULL,
`updated_at` TIMESTAMP NULL DEFAULT NULL
)
或者我应该为每个 table 重新创建一个 "duplicate",例如 user_history,然后在各自的列中添加历史记录
Users: id, name, surname ...
Users_history: id, user_id, name, surname ...
- 对这两种解决方案进行计时,您会发现哪一种更适合您。无法判断在您的应用程序和环境中哪个会更快。
这是一项设计决定,因此完全取决于您和您的要求。您需要考虑以下事项:
如果用户更改了交易中的记录,则所有受影响的字段将由同一用户同时更改。使用您建议的结构,所有这些更改都需要一个单独的条目。
使用您建议的结构,更难确定某条记录在给定时间点的样子,因为您基本上必须重播该记录插入后的所有更改。
在专业方面,所有更改都存储在一个 table 中,即使您更改数据库架构,也不必更改日志记录的结构。
您还必须考虑是要记录所有 table 的更改还是只记录部分选定的更改。
如果正在记录的 table 引用其他 table,您还需要考虑如何记录。例如,如果你想记录交易,那么你可能有一个交易类型字段和一个单独的交易类型 table 列出详细描述,也许还有关于每个交易类型的其他信息。如果一个交易类型不再被使用,那么它可以从交易类型中移除table或者它的参数可能会改变。
鉴于此架构:
CREATE TABLE contacts (
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`first_name` VARCHAR(255) NOT NULL COLLATE 'utf8_unicode_ci',
`last_name` VARCHAR(255) NOT NULL COLLATE 'utf8_unicode_ci',
`updated_by` VARCHAR(255) NOT NULL COLLATE 'utf8_unicode_ci',
`updated_at` TIMESTAMP NULL DEFAULT NULL
)
我也会创建这个架构:
CREATE TABLE contacts_audit (
`id` INT(10) UNSIGNED NOT NULL,
`first_name` VARCHAR(255) NOT NULL COLLATE 'utf8_unicode_ci',
`last_name` VARCHAR(255) NOT NULL COLLATE 'utf8_unicode_ci',
`updated_by` VARCHAR(255) NOT NULL COLLATE 'utf8_unicode_ci',
`updated_at` TIMESTAMP NULL DEFAULT NULL,
`action` varchar(255) NOT NULL COLLATE 'utf8_unicode_ci'
)
然后使用这些触发器(希望我的触发器语法不会太生疏):
CREATE TRIGGER contacts_audit_insert
AFTER INSERT
ON users FOR EACH ROW
BEGIN
INSERT INTO contacts_audit (id, first_name, last_name, updated_by, updated_at, action) values (NEW.id, NEW.first_name, NEW.last_name, NEW.updated_by, NEW.updated_at, 'insert');
END;
CREATE TRIGGER contacts_audit_update
AFTER UPDATE
ON users FOR EACH ROW
BEGIN
INSERT INTO contacts_audit (id, first_name, last_name, updated_by, updated_at, action) values (NEW.id, NEW.first_name, NEW.last_name, NEW.updated_by, NEW.updated_at, 'update');
END;
CREATE TRIGGER contacts_audit_delete
BEFORE DELETE
ON users FOR EACH ROW
BEGIN
INSERT INTO contacts_audit (id, first_name, last_name, updated_by, updated_at, action) values (OLD.id, OLD.first_name, OLD.last_name, OLD.updated_by, OLD.updated_at, 'delete');
END;
潜在缺点
如果您使用 MySQL username/password 进行数据库访问并根据 MySQL 中的 users
table 对您的用户进行身份验证,那么在执行任何操作之前删除,您需要在 PHP 内执行更新,然后执行删除,以便您可以捕获谁删除了您的记录。
但是,如果您使用 MySQL 对所有用户进行身份验证,那么您可以在触发器中使用:注意 USER()
INSERT INTO contacts_audit (id, first_name, last_name, updated_by, updated_at, action) values (NEW.id, NEW.first_name, NEW.last_name, USER(), NEW.updated_at, 'insert');