Если блокировка не выполняется должным образом, безусловно, возможно получить условие гонки этого типа, и режим блокировки по умолчанию (чтение зафиксировано) действительно позволяет это.В этом режиме только чтение устанавливает общую блокировку для записи, поэтому они могут одновременно видеть 0, увеличивать его и записывать 1 в базу данных.
Чтобы избежать этого условия гонки, необходимо установитьэксклюзивный замок на операцию чтения.Режимы параллелизма 'Serializable' и 'Repeatable Read' сделают это, и для операции над одной строкой они в значительной степени эквивалентны.
Чтобы сделать его полностью атомарным, вам необходимо:
- Установить соответствующий уровень изоляции транзакции , например, Serializable.Обычно это можно сделать из клиентской библиотеки или с помощью явного выражения в SQL.
- Начать транзакцию
- Считать данные
- Обновить их
- Подтвердить транзакцию.
Вы также можете принудительно установить эксклюзивную блокировку чтения с помощью HOLDLOCK (T-SQL) или эквивалентной подсказки, в зависимости от вашего диалекта SQL.
Один запрос на обновление сделает этоатомарно, но вы не можете разделить операцию (возможно, чтобы прочитать значение и вернуть его клиенту), не гарантируя, что чтения снимают монопольную блокировку. Вам нужно будет получить значение атомарно, чтобы реализовать последовательность , поэтому обновление само по себе, вероятно, не совсем то, что вам нужно. Даже при атомарном обновлении у вас все еще есть условие состязания, чтобы прочитать значение после обновления. Чтение все еще должно произойти в транзакции (сохранение того, что было получено в переменной) и выдать эксклюзивблокировка во время чтения.
Обратите внимание, что для этого без создания горячей точки ваша база данных должна иметь надлежащую поддержку автономных (вложенных) транзакций в рамках хранимой процедуры.Обратите внимание, что иногда «вложенный» используется для обозначения цепочек транзакций или точек сохранения, поэтому термин может быть немного запутанным.Я отредактировал это для ссылки на автономные транзакции.
Без автономных транзакций ваши блокировки наследуются родительской транзакцией, которая может откатить весь лот.Это означает, что они будут удерживаться до фиксации родительской транзакции, что может превратить вашу последовательность в «горячую точку», которая сериализует все транзакции, использующие эту последовательность.Все остальное, пытающееся использовать последовательность, будет блокироваться до тех пор, пока не будет принята вся родительская транзакция.
IIRC Oracle поддерживает автономные транзакции, но DB / 2 этого не было до недавнего времени, а SQL Server нет.Я не знаю, поддерживает ли их InnoDB, но Grey и Reuter довольно долго рассказывают о том, насколько сложно их реализовать.На практике, я думаю, вполне вероятно, что это не так.YMMV.