javascript — методы отслеживания изменений при обновлении веб-страницы в реальном времени.

Я хочу обновить список заказов (и статусов) в режиме реального времени на веб-странице. Заказы в базе данных (MySQL) обновляются асинхронно через другие процессы (PHP).

Я знаком с механизмом передачи данных на страницы (опрос, источник событий). Это не об этом.

Я борюсь с тем, чтобы выяснить, какие именно данные нужно отправить каждому пользователю без

  1. без необходимости обновлять список объектов, которые не должны быть
  2. не пропустите обновление.

В моей таблице есть столбец DateTime last_update_date что я обновляю, когда есть какие-либо изменения в заказе. Я знаю, что MySQL на самом деле не имеет никаких триггеров событий, которые могут вызвать другой код.

Идеи пока что:

  1. В моем JS я мог отслеживать время последнего запроса и при каждом последующем запросе запрашивать данные с того времени. Это не работает, потому что время JS, скорее всего, не будет соответствовать времени сервера MySQL.
  2. То же самое можно было бы сделать, храня время сервера в пользовательской сессии. Я чувствую, что это, вероятно, будет работать большую часть времени, но в зависимости от времени обновления БД и запросов, изменения могут быть пропущены, так как БД хранит только DateTime с точностью до 1 секунды.

Я уверен, что есть более атомарный способ сделать это, хотя я просто рисую пробел. Каковы подходящие шаблоны дизайна для этого?

1

Решение

Вы правы, что вы должны опросить свою базу данных на предмет изменений, и что 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 столбец опроса таблицы

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.

0

Другие решения

Решение, предоставленное O.Jones, будет работать для того, чтобы сделать отслеживание обновлений атомарным, хотя в этом случае происходит сбой, если следующий сценарий происходит в течение одной секунды:

  1. Обновление заказа записывается в таблицу (обновление 1)
  2. Происходит опрос
  3. Обновление заказа записывается в таблицу (обновление 2)

В этом случае следующее действие опроса будет либо пропустить обновление 2, либо дублировать обновление 1, в зависимости от того, используете ли вы > или же >= в вашем запросе. Это не ошибка кода, это ограничение типа datetime MySql с разрешением всего 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 которые имеют идентификатор больше идентификатора, сохраненного в сеансе, и присоединяют к нему заказы.

$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";

Теперь я гарантированно получу все заказы со времени последнего опроса, без дубликатов, и мне не нужно отслеживать отдельных клиентов.

0