Автор оригинала: Vlad Mihalcea.
Вступление
В этой статье я собираюсь объяснить, в чем разница между оптимистичной и пессимистичной блокировкой, а также когда вам следует использовать ту или иную стратегию управления параллелизмом.
Конфликты
На курсе сетевого взаимодействия в колледже я узнал, что существует два способа решения конфликтов или столкновений:
- обнаружьте и повторите попытку, и это именно то, что делает Ethernet
- избегайте их, блокируя другие одновременные передатчики, как это делает Wi-Fi .
Работа с конфликтами на самом деле одинакова даже при использовании системы баз данных.
Мы могли бы допустить возникновение конфликта, но тогда нам нужно обнаружить его при совершении вашей транзакции, и именно так работает оптимистичная блокировка.
Если стоимость повторной попытки высока, мы могли бы попытаться полностью избежать конфликта с помощью блокировки, которая является принципом, лежащим в основе того, как работает пессимистическая блокировка.
Аномалия потерянного обновления
Давайте рассмотрим аномалию потерянного обновления, которая может произойти в любой базе данных, работающей на уровне изоляции с фиксацией чтения:
На приведенной выше диаграмме показана следующая ситуация:
- Алиса считывает баланс счета, и значение
50
. - Сразу после этого Боб меняет баланс счета с
50
чтобы20
и совершает. - Транзакция Алисы все еще выполняется, и она думает, что баланс счета все еще
50
, она отстраняется40
думая, что окончательный баланс будет10
. - Однако, поскольку балдахин изменился, ОБНОВЛЕНИЕ Алисы оставит баланс счета в отрицательном значении.
Это расписание транзакций не сериализуемо, потому что оно не эквивалентно чтению и записи Алисы, за которыми следует чтение и запись Боба, или Бобу, сначала выполняющему свою транзакцию, а затем Алисе, выполняющей свою транзакцию сразу после этого.
Операции чтения и записи чередуются, и именно поэтому создается аномалия потерянного обновления.
Пессимистическая Блокировка
Пессимистическая блокировка направлена на предотвращение конфликтов с помощью блокировки.
На приведенной выше диаграмме и Алиса, и Боб получат блокировку чтения (общую) для строки учетной записи
таблицы при ее чтении.
Потому что и Алиса, и Боб удерживают блокировку чтения (общего доступа) для записи учетной записи
со значением идентификатора 1
, ни один из них не может изменить его, пока один из них не освободит блокировку чтения, которую они приобрели. Это связано с тем, что операция записи требует получения блокировки записи (эксклюзивной), а блокировки чтения (общие) предотвращают блокировку записи (эксклюзивную).
По этой причине ОБНОВЛЕНИЕ Боба блокируется до тех пор, пока Алиса не освободит общую блокировку, которую она приобрела ранее.
При использовании SQL Server база данных автоматически получает общие блокировки при чтении записи на уровне повторяемого чтения или сериализуемого уровня изоляции, поскольку SQL Server по умолчанию использует алгоритм 2PL (Двухфазная блокировка).
MySQL также использует пессимистическую блокировку по умолчанию при использовании сериализуемого уровня изоляции и оптимистическую блокировку для других менее строгих уровней изоляции.
Оптимистичная Блокировка
Оптимистическая блокировка допускает возникновение конфликта, но ее необходимо обнаружить во время записи. Это можно сделать с помощью физических или логических часов . Однако, поскольку логические часы превосходят физические часы, когда дело доходит до реализации механизма управления параллелизмом, мы собираемся использовать столбец версия
для записи информации о моментальном снимке строки во время чтения.
Столбец версия
будет увеличиваться каждый раз при выполнении инструкции UPDATE или DELETE, а также использоваться для сопоставления ожидаемого снимка строки в предложении WHERE.
Таким образом, при чтении записи учетной записи
оба пользователя читают ее текущую версию. Однако, когда Боб изменяет учетную запись
баланс, он также меняет версию с 1
чтобы 2
.
Впоследствии, когда Алиса захочет изменить учетную запись
баланс, выписка об ОБНОВЛЕНИИ не будет соответствовать ни одной записи, так как значение столбца версия больше не соответствует 1
, но 2
.
Следовательно, метод executeUpdate
ОБНОВЛЕНИЯ Preparedstatement
вернет значение 0
, что означает, что запись не была изменена, и базовая структура доступа к данным вызовет исключение OptimisticLockException
, которое приведет к откату транзакции Алисы.
Таким образом, потерянное обновление предотвращается путем отката последующих транзакций, которые работают с данными состояния.
В настоящее время многие системы реляционных баз данных используют оптимистическую блокировку для обеспечения гарантий ACID. Oracle, PostgreSQL и движок MySQL InnoDB используют MVCC (Управление параллелизмом нескольких версий) , который основан на оптимистичной блокировке.
Таким образом, в MVCC читатели не блокируют писателей, а писатели не блокируют читателей, позволяя возникать конфликтам. Однако во время фиксации механизм транзакций обнаруживает конфликты, и конфликтующие транзакции откатываются.
Транзакции на уровне приложений
Системы реляционных баз данных появились в конце 70-х и начале 80-х годов, когда клиенты подключались к мэйнфрейму через терминал. Однако в настоящее время это не так при использовании веб-браузера.
Таким образом, мы больше не выполняем операции чтения и записи в контексте одной и той же транзакции базы данных, и возможности сериализации больше недостаточно для предотвращения потери обновления в длительном разговоре .
Например, учитывая, что у нас есть следующий вариант использования:
Пессимистическая блокировка не помогла бы нам в этом случае, так как чтение и запись Алисы происходят в разных HTTP-запросах и транзакциях базы данных.
Таким образом, оптимистичная блокировка может помочь вам предотвратить потерю обновлений даже при использовании транзакций на уровне приложений, которые также включают время на обдумывание пользователем.
Вывод
Как пессимистическая, так и оптимистическая блокировка являются полезными методами. Пессимистическая блокировка подходит, когда стоимость повторной попытки транзакции очень высока или когда конкуренция настолько велика, что многие транзакции в конечном итоге откатились бы, если бы использовалась оптимистическая блокировка.
С другой стороны, оптимистическая блокировка работает даже в нескольких транзакциях базы данных, поскольку она не зависит от блокировки физических записей.