MySql: правильный уровень изоляции транзакции, чтобы использовать для увеличения числа - PullRequest
0 голосов
/ 10 сентября 2018

Предположим, есть таблица в БД, подобная этой:

id                                       code
a8e09395-771c-4c6b-bb49-4921eeaf3927    2018-1
726b1390-b502-11e8-96f8-529269fb1459    2018-2
7a7ac7a6-b502-11e8-96f8-529269fb1459    2018-3
81758ea6-b502-11e8-96f8-529269fb1459    2019-1

Предположим, что несколько клиентов пишут в эту таблицу.

Для столбца «код» мы хотим убедиться, что он соответствует шаблону строгий"year- nth этого года".

Каков правильный уровень изоляции транзакции, который должны использовать все клиенты?

---- обновление ---- 2018-09-11 11:31:24 ---------

START TRANSACTION;

SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;

SET @code = (SELECT CODE
             FROM hey
             WHERE id = 123);

UPDATE hey
SET code = @code + 1
WHERE id = 123;

COMMIT;

Сделал быстрый тест с вышеуказанной транзакцией.

Я запустил 2 консоли, затем запустил приведенный выше код, я запустил их обе в строку, которая читает столбец кода.

Затем заставьте одного из них обновить столбец кода, он будет ждать блокировки.

Затем я заставлю другой обновить столбец кода, он будет тупиковым и отката.

Теперь блокировка первой разрешена, и она может зафиксировать.

Так похоже, что эта изоляция транзакции может помешать им наступить друг другу на ногу, верно?

1 Ответ

0 голосов
/ 10 сентября 2018

Вам нужно решить это с блокировкой.

Неважно, какой уровень изоляции транзакции.

За один сеанс:

mysql1> begin;
mysql1> select max(code) from mytable where code like '2018-%' for update;

Выход:

+-----------+
| max(code) |
+-----------+
| 2017-3    |
+-----------+

Во втором сеансе попробуйте тот же выбор для обновления. Он останавливается, ожидая блокировки, удерживаемой транзакцией первого сеанса.

mysql2> begin;
mysql2> select max(code) from mytable where code like '2018-%' for update;
(waits for lock)

В первом сеансе используйте возвращаемое значение select для вычисления следующего значения. Затем вставьте следующую строку и зафиксируйте.

mysql1> insert into mytable values (uuid(), '2018-4');
mysql1> commit;

Второй сеанс возвращается сразу после коммита в первом сеансе. Правильно возвращает новый максимальный код:

+-----------+
| max(code) |
+-----------+
| 2017-4    |
+-----------+

Теперь у второго сеанса есть блокировка, и он может вставить следующую строку, не беспокоясь о том, что любой другой сеанс пробирается между select и insert.

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

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