检查用户是否更改了多个表中的任何数据

koj*_*ow7 9 php mysql database

在我的数据库中,我有几个表.一个是检查点表,记录用户选择完成其中一个项目.此表包含自动创建的时间戳.每当用户完成他们的项目时,都会在检查点表中添加一个新行(这样我们也可以保留项目最终确定的先前历史记录).

我还有其他几个带有时间戳的表(或者我也可以添加时间戳列的表),这些表会在表更改时自动更新.

是否有一种简单的方法可以判断自项目上次最终确定以来是否有其他表已更新其数据?我不需要知道哪些表已经更改了数据,只是存在已更改数据的表.

例如,如果用户更改其中一个表中的数据,我希望能够显示一条消息,指示其项目具有未终结的数据.

我有几种方法可以考虑这样做:

  1. 检查每个表以查看是否有任何时间戳比检查点表中的最新时间戳更新.
  2. 将另一个时间戳列(我已经创建并更新了时间戳列)添加到主项目表中.大多数其他表直接或间接链接到此主项目表.将触发器添加到每个其他表以在数据更改时更新此时间戳.我还不确定如何正确设置适当的触发器.
  3. 仅使用project_id和timestamp列创建新表.向其他表添加触发器,如选项2所示.

随着新模块的添加,我将在项目中添加更多表格,因此需要一些易于扩展的内容.

这些方法中的每一种似乎都涉及很多步骤.

这些方法中的一种比另一种方法更有效或更可行吗?还有另外一种我没想过的方法吗?如果触发器是执行此操作的最佳方式,我将如何设置触发器?

我的表的简化概述如下所示:

main_project_table
    id
    user_id (FK to user_table)
    created_timestamp
    updated_timestamp

checkpoint_group_table (users can choose which group to finalize their project too)
    id
    user_id (FK to user_table)
    group_name

checkpoint_table (the table that records the finalized data and time of finalization)
    id
    checkpoint_group_id (FK to checkpoint_group_table)
    project_id (FK to main_project_table)
    project_finalized_timestamp

 parent_table (several of these)
     id
     project_id (FK to main_project_table)

 child_table (0 or more of these for each parent_table)
     id
     parent_id (FK to parent_table)
Run Code Online (Sandbox Code Playgroud)

Jed*_*nch 5

您实际上只有三个解决方案:中间件,触发器和常规日志文件.

中间件解决方案:

timestamp向每个相关表添加一个字段,并将默认值设置为"CURRENT_TIMESTAMP".这将timestamp在每次更新时将字段更新为当前时间.假设用户正在浏览某些API,您可以编写JOIN查询,返回最新的时间戳.它看起来像这样.

SELECT
    CASE 
        WHEN b.timestamp IS NOT NULL THEN 0
        WHEN c.timestamp IS NOT NULL THEN 0
        WHEN d.timestamp IS NOT NULL THEN 0
        WHEN e.timestamp IS NOT NULL THEN 0
        ELSE 1
     AS `test`
FROM checkpoint_table a
LEFT JOIN main_project_table b 
    ON a.project_id = b.id 
    AND b.timestamp > a.project_finalized_timestamp
LEFT JOIN checkpoint_group_table c 
    ON b.user_id = c.user_id
    AND c.timestamp > a.project_finalized_timestamp
LEFT JOIN parent_table d 
    ON b.id = d.project_id
    AND d.timestamp > a.project_finalized_timestamp
LEFT JOIN child_table e ON d.id = e.parent_id
    ON b.id = d.project_id
    AND e.timestamp > a.project_finalized_timestamp
Run Code Online (Sandbox Code Playgroud)

现在,当请求路由到表时,您可以运行此查询,如果test == 0,则返回消息.

<?php
      class middleware{
          public function getMessage(){
              // run query

              if($data[0]['test'] == 1){
                   return "project has unfinalized data";
              }else{
                   return null;
              }
          }
      }
Run Code Online (Sandbox Code Playgroud)

触发解决方案:

CREATE TRIGGER checkpoint_group_table 
AFTER UPDATE on _table_
FOR EACH ROW UPDATE _table_  
SET main_project_table.updated_timestamp = CURTIME() 
WHERE main_project_table.user_id=checkpoint_group_table.id
Run Code Online (Sandbox Code Playgroud)

这样做的好处是它可能比中间件解决方案更优雅.缺点是触发器不是普通视图,而且我的经验是,当进程处于后台时,它们最终会被遗忘.从长远来看,你可能会留下这个Jenga拼图,这会让人感觉很难.

常规日志文件解决方案

Mysql可以记录服务器上的每个查询.可以在此期间访问此日志文件,将其解析出来,并确定是否更新了任何表.通过这种方式,您可以确定项目完成后是否有任何更新.

打开常规日志文件.

SET GLOBAL general_log = 'ON';
Run Code Online (Sandbox Code Playgroud)

设置日志文件的路径.

SET GLOBAL general_log_file = 'var/log/mysql/mysql_general.log'
Run Code Online (Sandbox Code Playgroud)

通过转到命令终端进行确认.

mysql -se "SHOW VARIABLES" | grep  -e general_log
Run Code Online (Sandbox Code Playgroud)

您可能需要重置MySQL.

sudo service MySQL restart
Run Code Online (Sandbox Code Playgroud)

你可以开始这个脚本......

$v = shell_exec("sudo less /var/log/mysql/mysql_general.log");

$lines = explode("\n",$v);

$new = array();
foreach($lines as $i => $line){
    if(substr($line,0,1) != " "){
        if(isset($l)){
            array_push($new,$l);
        }
        $l = $line;
    }else{
        $l.= preg_replace('/\s+/', ' ', $line);
    }
}

$lines = $new;

$index = array();
foreach($lines as $i => $line){
    $e = explode("\t",$line);
    $new = array();
    foreach($e as $key => $value){
        $new[$key] = trim($value);
    }

    $index[$i] = $new;

}
Run Code Online (Sandbox Code Playgroud)

这将导致...

array(3) {
  [0]=> string(27) "2017-10-01T08:17:04.659274Z"
  [1]=> string(8) "70 Query"
  [2]=> string(129) "UPDATE checkpoint_group_table SET group_name = 'Dev Group' Where id=6"
Run Code Online (Sandbox Code Playgroud)

}

从这里,您可以使用名为PHP-SQL-Parser的库来解析查询.

这种方法的优点可能很好地扩展,因为您不必向数据库添加任何列.缺点是这将涉及更多代码,这意味着更复杂.如果不为它编写单元测试,你可能无法真正做到这一点.


Rya*_*rne 1

进行多次检查时时间戳比较可能会很混乱。

...我不需要知道哪些表已更改数据,只需知道有些表已更改数据...

Join-query 生成 (1) 数据集,对其进行 JSON/SERIALIZE,然后进行 MD5,将此哈希字符串保存到 db 中。下次再对比一下,如果有不同,说明数据集已经改变了。这是大数据/文件比较/代码存储库中的一般思想。

但鉴于...

..项目的更多表格..

然后只需对表中的每个数据行使用 MD5。一旦更改,散列字符串就会不同。