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

kognpnkq  于 2021-06-20  发布在  Mysql
关注(0)|答案(2)|浏览(469)

我想在网页上实时更新订单(和状态)列表。(mysql)数据库中的命令通过其他进程(php)异步更新。
我熟悉将数据推送到页面的机制(轮询、事件源)。这与此无关。
我所要做的是弄清楚在没有数据的情况下为每个用户推送什么数据
不必要地更新不需要更新的列表实体
没有遗漏更新。
我的表没有datetime列 last_update_date 当订单有任何变化时我会更新。我知道mysql没有任何事件触发器可以触发其他代码。
目前的想法:
在我的js中,我可以跟踪最后一个请求的时间,并在随后的每个请求中,请求从那个时间开始的数据。这不起作用,因为js时间很可能与服务器mysql时间不匹配。
在用户会话中存储服务器时间也可以做到这一点。我觉得这在大多数情况下都可能有效,但是根据db更新的时间和请求,更改可能会丢失,因为db只存储精度为1秒的datetime。
我相信有一个更原子的方法可以做到这一点,但我只是画了一个空白。什么是合适的设计模式?

1bqhqjot

1bqhqjot1#

o.jones提供的解决方案可以使跟踪更新原子化,但如果在一秒钟内发生以下情况,则会失败:
订单更新写入表(更新1)
发生轮询操作
订单更新写入表(更新2)
在这种情况下,下一个轮询操作将错过更新2,或者将复制更新1,具体取决于您是否使用 > 或者 >= 在您的查询中。这不是代码的错误,而是mysql datetime类型只有1秒分辨率的限制。mysql v8可以在一定程度上缓解这种情况,因为它支持分秒,尽管这仍然不能保证原子性。
我最终使用的解决方案是创建一个 order_changelog

CREATE TABLE 'NewTable' (
'id'  int NULL AUTO_INCREMENT ,
'order_id'  int NULL ,
'update_date'  datetime NULL ,
PRIMARY KEY ('id')
);

每当对订单进行更改时,此表都会进行更新,基本上是对每次更新进行计算。
对于客户端,服务器存储 order_changelog 那是在会议上发出的。每次客户端轮询时,我都会从 order_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";

我现在可以保证拥有自上次投票以来的所有订单,没有重复订单,而且我不必跟踪单个客户。

ygya80vv

ygya80vv2#

正确的做法是,必须轮询数据库中的更改,mysql不能将更改推送到其他应用程序。
诀窍是在整个轮询过程中使用服务器时间。使用表跟踪轮询。例如,假设您的用户具有user\ id值。然后做一个 poll 表格包括

user_id  INT primary key
 polldate DATETIME

然后,当你投票做这个序列。
首先确保您的用户在 poll 显示很久以前 polldate . (insert ignore不会覆盖表中的任何现有行。)

SET @userid := <<your user's id>>;
 INSERT IGNORE INTO poll (user_id, polldate) VALUES (@userid, '1970-01-01')

当你投票的时候,做这一系列的操作。
锁定用户的轮询行:

BEGIN TRANSACTION;
 SELECT polldate INTO @polldate
   FROM poll
  WHERE user_id = @userid 
    FOR UPDATE;

检索所需的更新行;上次更新后的那些。

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;

每次使用此序列时,您都会从 transaction 自上次轮询以来已更新的表。如果没有项目,则 polldate 不会改变的。而且,都是服务器时间。
如果其他客户机更新select查询和update查询之间的事务表行,则需要该事务。

相关问题