Страницы

Поиск по вопросам

пятница, 29 ноября 2019 г.

Уровень изоляции транзакций и Hibernate

#java #sql #hibernate #orm #jpa


Первый вопрос. Какая связь существует между уровнем изоляции транзакций, параметрами
JPA Lock.READ / Lock.WRITE и версиями @Version (Оптимистическая блокировка)? Я более
менее понял по отдельности каждую из этих 3 разделов, но не понимаю, как они связаны
между собой.  Выбранный уровень изоляции транзакций дает некие «гарантии» при проведении
операций с таблицами.  Параметры Lock.READ/Lock.WRITE позволяют добиться блокировки
полей таблицы при проведении операций. Если я правильно понял, для этого как раз и
используются поле @Version.  Но все таки не до конца улавливаю связь между эти тремя
понятиями. Или они дополняют друг друга, или это разные способы решения одних и тех
же проблем. В общем, буду очень благодарен за ответ или же ссылку, где можно прочесть
информацию именно по вопросы связи между этими понятиями и их совместном использовании.
Второй вопрос. Каким способом в Hibernate можно указать требуемый уровень изоляции
транзакции для конкретной транзакции? И принято ли так делать?
Спасибо.    


Ответы

Ответ 1



Попробую ответить по порядку: Как соотносятся Lock и уровни изоляции Уровень изоляции транзакций (transaction isolation level) - относится к чтению данных, но не к записи данных; Lock относится к доступу к данным (то есть затрагивает и чтение и запись и модификацию); Можно сказать так, что механизм Lock обеспечивает работоспособность различных уровней изоляции данных, в самом тупом примере: если у вас стоит уровень изоляции READ_COMMITTED, то вставка произведенная параллельной сессией будет локирована на запись пока сессия не выдаст commit(), но лок на чтение будет открыт сразу при запросе вашего select, а при REPEATABLE_READ оба лока (на чтение и запись) будут стоять до commit() - соответственно ваш select увидит результаты модификации только после коммита. Каким способом в Hibernate можно указать требуемый уровень изоляции транзакции для конкретной транзакции? Вообще это не сильно здорово. Уровень изоляции транзакций это принадлежность коннекта к БД, соответственно фактически изменение уровня изоляции равносильно переконнекту к БД, а насколько это дорогая операция вы сами можете оценить исходя из имеющейся у вас ситуации. Тем не менее, если вы таки решили менять перед каждой транзакцией уровень изоляции транзакций, то самый простой способ это отправить в СУБД raw SQL query (любой ORM это поддерживает), типа: ALTER SESSION SET ISOLATION_LEVEL SERIALIZABLE

Ответ 2



Вопрос лёгкий, но ответ слишком длинный. Лучше книжки почитать. Уровни изоляции, блокировки настоящие и оптимистические - работают каждый над своей проблемой. Прямо они не связаны. Подбирая их комбинацию, получаете то, что Вам нужно. В jpa предусмотрены как оптимистичные режимы блокировки (полностью полагаются на @Version), так и пессимистичные (которые выполняются сервером базы данных): OPTIMISTIC (он же READ) OPTIMISTIC_FORCE_INCREMENT (он же WRITE) PESSIMISTIC_READ PESSIMISTIC_WRITE PESSIMISTIC_FORCE_INCREMENT Как изменить уровень изоляции. Если управляете транзакцией самостоятельно, то и меняйте как хотите (сonnection.setTransactionIsolation? Нужно только connection извлечь из entity из managera). А например JTA изменить вряд ли получится. Там уровень задаётся в конфигурации datasource и изменение его не предполагается. Кажется именно так. Хотя можете уточнить этот момент. Всё течёт, всё изменяется. Может это уже не так.

Ответ 3



Некоторую информацию по данному вопросу можно почерпнуть из статьи с хабра UPD по второму вопросу: Аннотация @Transactional указывает, что метод должен выполняться в транзакции. Менеджер транзакций открывает новую транзакцию и создаёт для неё экземпляр Session, который доступен через sessionFactory.getCurrentSession(). Все методы, которые вызываются в методе с данной аннотацией, также имеют доступ к этой транзакции, потому что экземпляр Session является переменной потока (ThreadLocal). Вызов sessionFactory.openSession() откроет совсем другую сессию, которая не связана с транзакцией. Параметр rollbackFor указывает исключения, при выбросе которых должен быть произведён откат транзакции. Есть обратный параметр — noRollbackFor, указывающий, что все исключения, кроме перечисленных, приводят к откату транзакции. Параметр propagation самый интересный. Он указывает принцип распространения транзакции. Может принимать любое значение из перечисления org.springframework.transaction.annotation.Propagation. Propagation.REQUIRED — выполняться в существующей транзакции, если она есть, иначе создавать новую. Propagation.MANDATORY — выполняться в существующей транзакции, если она есть, иначе генерировать исключение. Propagation.SUPPORTS — выполняться в существующей транзакции, если она есть, иначе выполняться вне транзакции. Propagation.NOT_SUPPORTED — всегда выполняться вне транзакции. Если есть существующая, то она будет остановлена. Propagation.REQUIRES_NEW — всегда выполняться в новой независимой транзакции. Если есть существующая, то она будет остановлена до окончания выполнения новой транзакции. Propagation.NESTED — если есть текущая транзакция, выполняться в новой, так называемой, вложенной транзакции. Если вложенная транзакция будет отменена, то это не повлияет на внешнюю транзакцию; если будет отменена внешняя транзакция, то будет отменена и вложенная. Если текущей транзакции нет, то просто создаётся новая. Propagation.NEVER — всегда выполнять вне транзакции, при наличии существующей генерировать исключение.

Комментариев нет:

Отправить комментарий