Я хочу обновить список заказов (и статусов) в режиме реального времени на веб-странице. Заказы в базе данных (MySQL) обновляются асинхронно через другие процессы (PHP).
Я знаком с механизмом передачи данных на страницы (опрос, источник событий). Это не об этом.
Я борюсь с тем, чтобы выяснить, какие именно данные нужно отправить каждому пользователю без
В моей таблице есть столбец DateTime last_update_date
что я обновляю, когда есть какие-либо изменения в заказе. Я знаю, что MySQL на самом деле не имеет никаких триггеров событий, которые могут вызвать другой код.
Идеи пока что:
Я уверен, что есть более атомарный способ сделать это, хотя я просто рисую пробел. Каковы подходящие шаблоны дизайна для этого?
Вы правы, что вы должны опросить свою базу данных на предмет изменений, и что 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.
Решение, предоставленное O.Jones, будет работать для того, чтобы сделать отслеживание обновлений атомарным, хотя в этом случае происходит сбой, если следующий сценарий происходит в течение одной секунды:
В этом случае следующее действие опроса будет либо пропустить обновление 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";
Теперь я гарантированно получу все заказы со времени последнего опроса, без дубликатов, и мне не нужно отслеживать отдельных клиентов.