Как механизмы блокировки (пессимистичные / оптимистические) связаны с уровнями изоляции транзакций базы данных?

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

Я смотрел на уровни изоляции транзакций, и теперь я немного запутался. Похоже, разные уровни изоляции транзакций также решают аналогичные проблемы.

Как эти два разных понятия связаны друг с другом? Если возможно, с простым примером.

2 ответа

Решение

Обе эти вещи связаны с согласованностью данных и одновременным доступом, но это два разных механизма.

Блокировка предотвращает одновременный доступ к некоторому объекту. Например, когда вы пытаетесь обновить элемент списка задач, база данных с пессимистической блокировкой устанавливает блокировку строки на запись до тех пор, пока вы не подтвердите или не откатите транзакцию, так что никакая другая транзакция не может обновить эту запись. Оптимистическая блокировка - это проверка на стороне приложения, изменилась ли временная метка / версия записи между выборкой и попыткой ее обновления. Это независимо от уровня изоляции транзакции.

Изоляция транзакции заключается в согласованности чтения.

  • Чтение незафиксированного уровня позволяет сеансу видеть незафиксированные изменения другого сеанса
  • Уровень фиксации чтения позволяет сеансу видеть только зафиксированные изменения другого сеанса
  • Сериализуемый уровень позволяет сеансу видеть только изменения, зафиксированные до начала транзакции.

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

SESSION 1                                  SESSION 2
--------------------------------           --------------------------------------
SELECT count(*) FROM test;
=> 10
                                           INSERT INTO test VALUES ('x');

SELECT count(*) FROM test;
=> 10 with read committed/serializable
=> 11 with read uncommited (dirty read)
                                           COMMIT;

SELECT count(*) FROM test;
=> 10 with serializable
=> 11 with read uncommitted/read committed

Существует четыре уровня изоляции транзакций, указанных ANSI (один из которых не упоминается в приведенном выше примере как "повторяемое чтение"), все они, кроме сериализуемого, подвержены некоторым аномалиям. Обратите внимание, что это не имеет ничего общего с блокировкой.

Вы можете взглянуть на документацию Oracle по этому вопросу здесь, концепции довольно универсальны.

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

Механизмы блокировки обычно используются для реализации уровней изоляции транзакций. Таким образом, уровни изоляции транзакций определяют контракт, как ваши транзакции должны вести себя при параллельном выполнении. Механизмы блокировки являются деталями реализации.

С точки зрения написания приложения вы должны сосредоточиться на установке соответствующего уровня изоляции транзакции. Конечно, установка определенного уровня изоляции подразумевает блокировку, но пока ваше приложение не находится под большой нагрузкой, вам не нужно много о нем заботиться.

Важным моментом является то, что механизмы блокировки различаются в зависимости от ядра базы данных Если вы пишете приложение для одной базы данных и через какое-то время вы меняете движок базы данных, ваше приложение может вести себя по-другому, или некоторая его часть может потребовать переписывания.

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

Другие вопросы по тегам