Подтвердить что ты не робот

Как Hibernate определяет порядок обновления/вставки/удаления

Пусть сначала забудет о Спящем. Предположим, что у меня есть две таблицы: A и B. Две транзакции обновляют одни и те же записи в этих двух таблицах, но txn 1 update B, а затем A, а txn 2 - обновление A, затем B. Это типичный пример взаимоблокировки. Наиболее распространенным способом избежать этого является предварительное определение порядка приобретения ресурсов. Например, мы должны обновить таблицу A, затем B.

Вернитесь в спящий режим. Когда мы обновляем множество сущностей за один сеанс, как только я очищаю сессию, изменения разных сущностей будут генерировать соответствующие операторы вставки/обновления/удаления в БД. Есть ли у Hibernate алгоритм для определения порядка обновления среди объектов? Если нет, то каким образом Hibernate используется для предотвращения ситуации взаимоблокировки, описанной в 1-м абзаце?

Если Hibernate поддерживает порядок, как я могу узнать или контролировать заказ? Я не хочу, чтобы мое явное обновление в БД конфликтует с Hibernate и вызывает тупик.

4b9b3361

Ответ 1

Проблема, которую вы описываете, не обрабатывается базой данных, и по моему опыту также не полностью выполняется Hibernate.

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

Hibernate выполняет некоторые работы для вас. В соответствии с предыдущим ответом Hibernate гарантирует, что в изолированном флеше вставки, удаления и обновления упорядочиваются таким образом, чтобы обеспечить их применение в достижимом порядке. См. performExecutions (сеанс EventSource) в классе AbstractFlushingEventListener:

Выполнять все SQL (и обновления второго уровня) в специальном порядке, чтобы ограничения внешнего ключа не могли быть нарушены:

  • Вставляет, в порядке их выполнения.
  • Обновления
  • Удаление элементов коллекции
  • Вставка элементов коллекции
  • Удаляет, в порядке их выполнения.

При наличии уникальных ограничений очень важно знать этот порядок, особенно если вы хотите заменить дочерний элемент "один ко многим" (удалить старый/вставить новый), но как старый, так и новый дочерние пользователи имеют одинаковые уникальные ограничения (например, тот же адрес электронной почты). В этом случае вы можете обновить старую запись вместо удаления/вставки или вы можете выполнить очистку после удаления, а затем продолжить вставку. Для более подробного примера вы можете проверить эту статью.

Обратите внимание, что он не определяет порядок обновлений. Рассмотрение кода Hibernate приводит меня к мысли, что порядок обновления будет зависеть от порядка, в котором сущности были добавлены в контекст персистентности, НЕ порядок их обновления. Это может быть предсказуемо в вашем коде, но чтение кода Hibernate не оставляло меня в покое, я бы полагался на этот заказ.

Есть три решения, о которых я могу думать:

  • Попробуйте установить hibernate.order_updates, чтобы быть правдой. Это должно помочь избежать взаимоблокировок при обновлении нескольких строк в одной таблице, но не поможет с взаимоблокировками в нескольких таблицах.
  • Сделайте свои транзакции с помощью PESSIMISTIC_WRITE блокировки на одном из объектов перед выполнением любых обновлений. Какая сущность, которую вы используете, будет зависеть от вашей конкретной ситуации, но пока вы гарантируете, что сущность будет выбираться последовательно, если существует риск тупика, это блокирует остальную транзакцию до тех пор, пока не будет получена блокировка.
  • Напишите свой код, чтобы поймать тупики, когда они произойдут, и повторите попытку разумным способом. Компонент, управляющий повторной попыткой блокировки блокировки, должен располагаться за пределами текущей границы транзакции. Это связано с тем, что сеанс сбоя должен быть закрыт, а связанная транзакция - с обратной связью. В в этой статье вы можете найти пример автоматического повторного ASP Apect.

Ответ 2

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

Что касается Hibernate, javadoc to org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(EventSource) говорит:

Выполнять все обновления кэша SQL и второго уровня в специальном порядке, чтобы ограничения внешних ключей не могли быть нарушены:

  • Вставляет, в порядке их выполнения.
  • Обновления Удаление элементов коллекции
  • Вставка элементов коллекции
  • Удаляет, в порядке их выполнения.

Я предполагаю, что это единственная оптимизация выполненных SQL-запросов, создаваемых Hibernate. Остальные проблемы обрабатываются базой данных.