Зачем мне использовать уровень изоляции Repeatable Read (или более высокий), если мне нужно прочитать версию во второй раз?

Я прочитал главу книги Мартина Фаулера Optimistic Offline Lock

Автор описывает следующий пример (если я правильно понял):

Есть 2 объекта: Order и Client. Участвуют 2 сделки (бизнес):

  1. Первая транзакция рассчитывает сумму налога на заказ. Сумма налогов зависит от пунктов Заказа и адреса клиента.

  2. Вторая транзакция обновляет адрес клиента

Проблема здесь в том, что если client адрес будет изменен при расчете суммы налогов order, результат может быть противоречивым. Авторы предложили 2 решения, основанные на оптимистичной автономной блокировке. Один из них - проверка версий order и client в начале транзакции и проверка версий order и client в конце транзакции. Но здесь автор предупреждает, что мы должны использовать уровень изоляции REPEATABLE READ или выше, чтобы иметь возможность читать версии второй раз. Это причина моего вопроса. Насколько я понимаю, если я прочитаю любую строку во второй раз, я получу тот же результат, потому что при использовании этого уровня изоляции БД блокирует все строки, которые мы читали раньше.

Объясните, пожалуйста, автор идеи.


person gstackoverflow    schedule 14.10.2019    source источник


Ответы (2)


Мне также трудно понять эту часть книги. Но вроде все было очень просто. Сначала позвольте мне скопировать этот абзац из книги:

Нет причин, по которым Optimistic Offline Lock нельзя использовать для обнаружения несогласованного чтения. В приведенном выше примере сеанс начисления платы должен учитывать, что его правильность зависит от значения адреса клиента. Следовательно, он должен также выполнить проверку версии адреса, возможно, добавив адрес в набор изменений или поддерживая отдельный список элементов для проверки версии. Последнее требует немного больше работы для настройки, но в результате получается код, который более четко заявляет о его намерениях. Если вы проверяете непротиворечивое чтение, просто перечитывая версию, а не искусственно обновляя, особенно обратите внимание на уровень изоляции транзакций вашей системы. Повторное чтение версии будет работать только с повторяющимся чтением или более сильной изоляцией. Что-нибудь более слабое требует увеличения версии.

Здесь автор просто означает, что в случае Repeatable-Read и более сильного уровня транзакции вы также можете преодолеть эти проблемы. Вы выберете Client Address в начале транзакции, и Repeatable-Read заблокирует эту строку в таблице, и в результате вторая транзакция не сможет изменить какую-либо информацию об адресе.

Важно помнить следующее:

В случае Repeatable-Read каждая блокировка, полученная во время транзакции, удерживается на время транзакции.

person Farhad Jabiyev    schedule 23.08.2020

DB блокирует все строки, которые мы читали раньше, только если это требуется. REPEATABLE READ уровень изоляции - это минимальный уровень, требующий этого. Из документов PG:

Read Committed - это уровень изоляции по умолчанию в PostgreSQL. Когда транзакция использует этот уровень изоляции, запрос SELECT (без предложения FOR UPDATE / SHARE) видит только данные, зафиксированные до начала запроса; он никогда не видит ни незафиксированных данных, ни изменений, зафиксированных во время выполнения запроса параллельными транзакциями. Фактически, запрос SELECT видит моментальный снимок базы данных в момент начала выполнения запроса. Однако SELECT видит эффекты предыдущих обновлений, выполненных в его собственной транзакции, даже если они еще не зафиксированы. Также обратите внимание, что две последовательные команды SELECT могут видеть разные данные, даже если они находятся в одной транзакции, если другие транзакции фиксируют изменения после запуска первого SELECT и до запуска второго SELECT.

Если вы работаете с REPEATABLE READ + уровнем изоляции, ваша транзакция удерживает блокировку чтения записи. Таким образом, обновление либо будет успешным, либо откат всей транзакции (в случае взаимоблокировки с другой транзакцией, пытающейся сделать тот же PG, уничтожит одну транзакцию, чтобы разрешить ее).

Если вы работаете с READ COMMITTED уровнем изоляции, вы не удерживаете блокировку. Если другая транзакция изменит поле версии до того, как вы это сделаете, ваше ОБНОВЛЕНИЕ ничего не обновит (executeUpdate вернет 0). Так что вы можете проверить это и действовать соответственно.

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

person Konstantin Triger    schedule 15.10.2019
comment
1. Я не понял, что вы имели в виду в абзаце о повторяющемся чтении (после цитаты). Не могли бы вы перефразировать? Я имею в виду, что если мы можем читать данные на уровне изоляции Repeatable Read - это означает, что другие транзакции не могут изменять эти строки до завершения нашей транзакции. 2. Также я не получил ответа на вопрос, что хотел сказать Мартин Фаулер? - person gstackoverflow; 19.10.2019