用于数据审计的MySQL Trigger或PHP?

时间:2016-03-16 17:41:34

标签: php mysql laravel version-control revision

我希望在我的应用程序中保留表的每次更新的历史记录。我正在使用Laravel,我知道有一些包可以帮助我,但我看起来干净又快。

我有两个选择:

  • MySQL触发器
  • 通过PHP代码

我的第一个问题是,哪一个更快?

我的第二个问题是: 我应该使用这样的模式并将所有表存储到其中:

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
)

或者我应该重新创建每个表的“重复”,例如user_history,并在相应的列上添加历史记录

Users: id, name, surname ...
Users_history: id, user_id, name, surname ... 

2 个答案:

答案 0 :(得分:1)

  1. 时间两个解决方案,您将看到哪一个更快地为您工作。在您的应用程序和环境中,无法确定哪个更快。
  2. 这是一个设计决定,因此它取决于您和您的要求。您需要考虑以下事项:

    • 如果用户更改了事务中的记录,则同一用户将同时更改所有受影响的字段。根据您建议的结构,所有这些更改都需要单独输入。

    • 使用您提出的结构确定某个特定记录在给定时间点的样子更加困难,因为您基本上必须从插入中重放该记录的所有更改。

    • 在专业方面,所有更改都存储在一个表中,即使您更改了数据库架构,也不必更改日志记录的结​​构。

    • 您还必须考虑是否要记录所有表格的更改或仅记录一些选定的表格。

    • 如果要记录的表引用其他表,您还需要考虑如何记录。例如,如果要记录事务,那么您可能有一个事务类型字段和一个单独的事务类型表,其中列出了详细描述以及可能有关每种事务类型的其他信息。如果不再使用事务类型,则可以从事务类型表中删除它,或者它的参数可能会更改。

答案 1 :(得分:0)

鉴于此架构:

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用户名/密码进行数据库访问并根据MySQL中的users表对用户进行身份验证,那么在执行任何删除之前,您需要在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');