Javascript 对网页进行实时更新时跟踪更改的方法

Javascript 对网页进行实时更新时跟踪更改的方法,javascript,php,mysql,atomicity,eventsource,Javascript,Php,Mysql,Atomicity,Eventsource,我希望在网页上实时更新订单(和状态)列表。(MySQL)数据库中的订单通过其他进程(PHP)异步更新 我熟悉将数据推送到页面的机制(轮询、事件源)。这与此无关 我所要做的是弄清楚,在没有数据的情况下,每个用户到底需要推送哪些数据 不必要地更新不需要更新的列表实体 没有遗漏更新 我的表确实有一个DateTime列last\u update\u date,当订单发生任何更改时,我会更新该列。我知道MySQL实际上没有任何可以触发其他代码的事件触发器 迄今为止的想法: 在我的JS中,我可以跟踪最后一个

我希望在网页上实时更新订单(和状态)列表。(MySQL)数据库中的订单通过其他进程(PHP)异步更新

我熟悉将数据推送到页面的机制(轮询、事件源)。这与此无关

我所要做的是弄清楚,在没有数据的情况下,每个用户到底需要推送哪些数据

  • 不必要地更新不需要更新的列表实体
  • 没有遗漏更新
  • 我的表确实有一个DateTime列
    last\u update\u date
    ,当订单发生任何更改时,我会更新该列。我知道MySQL实际上没有任何可以触发其他代码的事件触发器

    迄今为止的想法:

  • 在我的JS中,我可以跟踪最后一个请求的时间,并在随后的每个请求中,请求自该时间起的数据。这不起作用,因为JS时间很可能与服务器MySQL时间不匹配
  • 在用户会话中存储服务器时间也可以做到这一点。我觉得这可能在大多数情况下都有效,但根据数据库更新的时间和请求,更改可能会丢失,因为数据库只存储精度为1秒的日期时间

  • 我确信有一种更原子化的方法可以做到这一点,不过我只是画了一张空白。什么是适合这种情况的设计模式?

    您必须轮询数据库以获取更改,MySQL不能将更改推送到其他应用程序,这是正确的

    诀窍是在整个轮询过程中使用服务器时间。使用表格跟踪轮询。例如,假设您的用户具有用户id值。然后制作一个
    poll
    表格,包括

     user_id  INT primary key
     polldate DATETIME 
    
    然后,当你投票时,做这个序列

    首先确保您的用户在
    poll
    表中有一个条目,显示很久以前的
    polldate
    。(INSERT IGNORE不会覆盖表中的任何现有行。)

    检索所需的更新行;自上次更新以来的

     SELECT t.whatever, t.whatelse
       FROM transaction_table t
       JOIN poll p ON t.user_id = p.user_id
      WHERE user_id = @userid
        AND t.last_update_date > p.polldate;
    
    更新
    poll
    表的polldate列

    UPDATE poll p
       SET p.polldate = IFNULL(MAX(t.last_update_date), p.polldate)
      FROM transaction_table t
      JOIN poll_p ON t.user_id = p.user_id
      WHERE user_id = @userid
        AND t.last_update_date > p.polldate;
    
    并提交事务

     COMMIT;
    
    每次使用此序列时,您都会从
    事务
    表中获取自上次轮询以来已更新的项目。如果没有项目,
    polldate
    将不会更改。而且,这一切都是在服务器时间


    您需要该事务,以防其他客户端更新SELECT和UPDATE查询之间的事务表行

    O.Jones提供的解决方案可以使跟踪更新原子化,但如果在一秒钟内发生以下情况,则该解决方案会失败:

  • 订单更新写入表(更新1)
  • 发生轮询操作
  • 订单更新写入表(更新2)
  • 在这种情况下,下一个轮询操作将错过更新2,或复制更新1,具体取决于您在查询中使用的是
    还是
    =
    。这不是代码的错误,这是MySql datetime类型只有1秒分辨率的限制。MySql v8可以在一定程度上缓解这一问题,尽管这仍然不能保证原子性

    我最终使用的解决方案是创建一个
    order\u changelog

    CREATE TABLE 'NewTable' (
    'id'  int NULL AUTO_INCREMENT ,
    'order_id'  int NULL ,
    'update_date'  datetime NULL ,
    PRIMARY KEY ('id')
    );
    
    每当对订单进行更改时,此表都会更新,基本上是对每次更新进行计算

    对于客户端,服务器存储会话中发送的来自
    order\u changelog
    的最后一个ID。每次客户端轮询时,我都会从
    order\u changelog
    中获取ID大于会话中存储的ID的所有行,并将订单加入其中

    $last_id = $_SESSION['last_update_id'];
    
    $sql = "SELECT o.*, c.id as update_id
                    FROM order_changelog c
                    LEFT JOIN orders o ON c.order_id = o.id
                    WHERE c.id > $last_id
                    GROUP BY o.id
                    ORDER BY order_date";
    
    我现在保证拥有自上次投票以来的所有订单,没有重复订单,而且我不必跟踪个别客户

    CREATE TABLE 'NewTable' (
    'id'  int NULL AUTO_INCREMENT ,
    'order_id'  int NULL ,
    'update_date'  datetime NULL ,
    PRIMARY KEY ('id')
    );
    
    $last_id = $_SESSION['last_update_id'];
    
    $sql = "SELECT o.*, c.id as update_id
                    FROM order_changelog c
                    LEFT JOIN orders o ON c.order_id = o.id
                    WHERE c.id > $last_id
                    GROUP BY o.id
                    ORDER BY order_date";