Ответ 1
Проблема, которую вы описываете, не обрабатывается базой данных, и по моему опыту также не полностью выполняется Hibernate.
Вам нужно предпринять явные шаги, чтобы избежать проблем.
Hibernate выполняет некоторые работы для вас. В соответствии с предыдущим ответом Hibernate гарантирует, что в изолированном флеше вставки, удаления и обновления упорядочиваются таким образом, чтобы обеспечить их применение в достижимом порядке. См. performExecutions (сеанс EventSource) в классе AbstractFlushingEventListener:
Выполнять все SQL (и обновления второго уровня) в специальном порядке, чтобы ограничения внешнего ключа не могли быть нарушены:
- Вставляет, в порядке их выполнения.
- Обновления
- Удаление элементов коллекции
- Вставка элементов коллекции
- Удаляет, в порядке их выполнения.
При наличии уникальных ограничений очень важно знать этот порядок, особенно если вы хотите заменить дочерний элемент "один ко многим" (удалить старый/вставить новый), но как старый, так и новый дочерние пользователи имеют одинаковые уникальные ограничения (например, тот же адрес электронной почты). В этом случае вы можете обновить старую запись вместо удаления/вставки или вы можете выполнить очистку после удаления, а затем продолжить вставку. Для более подробного примера вы можете проверить эту статью.
Обратите внимание, что он не определяет порядок обновлений. Рассмотрение кода Hibernate приводит меня к мысли, что порядок обновления будет зависеть от порядка, в котором сущности были добавлены в контекст персистентности, НЕ порядок их обновления. Это может быть предсказуемо в вашем коде, но чтение кода Hibernate не оставляло меня в покое, я бы полагался на этот заказ.
Есть три решения, о которых я могу думать:
- Попробуйте установить hibernate.order_updates, чтобы быть правдой. Это должно помочь избежать взаимоблокировок при обновлении нескольких строк в одной таблице, но не поможет с взаимоблокировками в нескольких таблицах.
- Сделайте свои транзакции с помощью PESSIMISTIC_WRITE блокировки на одном из объектов перед выполнением любых обновлений. Какая сущность, которую вы используете, будет зависеть от вашей конкретной ситуации, но пока вы гарантируете, что сущность будет выбираться последовательно, если существует риск тупика, это блокирует остальную транзакцию до тех пор, пока не будет получена блокировка.
- Напишите свой код, чтобы поймать тупики, когда они произойдут, и повторите попытку разумным способом. Компонент, управляющий повторной попыткой блокировки блокировки, должен располагаться за пределами текущей границы транзакции. Это связано с тем, что сеанс сбоя должен быть закрыт, а связанная транзакция - с обратной связью. В в этой статье вы можете найти пример автоматического повторного ASP Apect.