Методы отслеживания изменений при обновлении веб-страницы в реальном времени. - PullRequest
0 голосов
/ 05 октября 2018

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

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

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

  1. ненужного обновления объектов списка, которые не нужно
  2. не пропущено обновление.

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

Пока что есть идеи:

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

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

Ответы [ 2 ]

0 голосов
/ 08 октября 2018

Решение, предоставленное 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 голосов
/ 05 октября 2018

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

...