MySQL параллелизма и авто_инкрементный ключ - PullRequest
0 голосов
/ 22 октября 2018

У меня есть таблица пользователей MySQL и таблица действий, выполняемых пользователями (связаны с этим пользователем первичным ключом, идентификатор пользователя ).Таблица действий имеет увеличивающийся ключ indx .Всякий раз, когда я добавляю новую строку в эту таблицу, я обновляю столбец latest соответствующей строки Users на indx строки, которую я только что добавил в таблицу Actions.Так что-то вроде:

INSERT INTO actions(indx,actionname,userid) VALUES(default, "myaction", 1);
UPDATE users SET latest=LAST_INSERT_ID() WHERE userid=1;

Идея в том, что я могу проверить наличие обновлений для Пользователя, посмотрев, является ли последний выше, чем в прошлый раз, когда я проверял.

Моя проблема заключается в том, что если в базе данных открыто более одного соединения, и они пытаются одновременно добавить действие для одного и того же пользователя, то соединение 2 может запускать свои INSERT и UPDATE между INSERT и обновлениемconnection1, и последняя запись пользователя, которого они пытаются обновить, больше не будет иметь indx самой последней записи действия.

У меня естьчитал о транзакциях, уровнях изоляции и т. д. Но на самом деле не нашел способа обойти это (хотя мое понимание того, как именно они работают, довольно шатко, поэтому, может быть, я просто неправильно понял).Я думаю, что мне нужен способ заблокировать таблицу действий, пока таблица пользователя не будет обновлена.Это приложение используется только несколькими сотнями пользователей, поэтому я не думаю, что снижение производительности из-за мгновенной блокировки таблицы будет слишком плохим.

Так что же можно сделать в MySQL?Есть ли лучшее решение?Я предполагаю, что этот общий шаблон должен быть довольно распространенным: иметь одну таблицу с кучей разновидностей строк и вторую таблицу со строкой, которая отслеживает метаданные для каждого сорта в таблице A и должна обновляться атомарно каждый раз, когда первая таблицаизменилось.Поэтому я надеюсь, что есть решение, которое не слишком сложно

1 Ответ

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

Используйте SELECT ... FOR UPDATE , чтобы заблокировать строку, чтобы сериализовать доступ к таблице и предотвратить условия гонки:

START TRANSACTION;
SELECT any_column FROM users WHERE userid=1 FOR UPDATE;
INSERT INTO actions(indx,actionname,userid) VALUES(default, "myaction", 1);
UPDATE users SET latest=LATEST_INSERT_ID() WHERE userid=1;
COMMIT;

Однако это будетзамедлите вашу скорость ВСТАВКИ , потому что все эти транзакции из всех сессий будут сериализованы.


Лучшая опция i s - вообще не хранить последний идентификатор в таблице users.Просто используйте SELECT max( id ) FROM actions WHERE userid = xxxx во всех местах, где требуется этот номер.С индексом actions( userid ) этот запрос будет очень быстрым (при условии, что столбец id является первичным ключом в этой таблице), и вставки не будут замедлены

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...