Нахождение тупиков
тупиков очень трудно найти. Если вы знаете, почему они происходят, вы можете воспроизвести это в интеграционных тестах. В реальных условиях вы можете использовать Profiler для наблюдения за мертвыми замками. Он показывает график, который показывает, как образуется тупик.
Retry
Вы должны выбросить транзакцию и начать заново. Сеанс NHibernate не синхронизируется после любого исключения из базы данных.
У нас есть задержка перед перезапуском, чтобы избежать дополнительной нагрузки на базу данных. Он ожидает некоторое время, содержащее случайное число, чтобы избежать повторной синхронизации параллельных транзакций.
Как избежать тупиков
Сокращение времени блокировки
Если вы используете Sql Server, он очень уязвим для мертвых блокировок из-за своего пессимистического механизма блокировки (в отличие от баз данных Oracle). Более новый уровень изоляции Snapshot чем-то похож на то, что делает Oracle, и может в некоторой степени решить проблему, но я никогда не использовал до сих пор, поэтому я не могу много говорить об этом.
NHibernate по возможности устраняет проблему, кэшируя изменения в постоянных данных и сохраняя их в конце транзакции. Но есть некоторые ограничения и способы его преодоления.
Использование идентификатора («авто номера») в качестве первичных ключей, вероятно, является самой известной ошибкой . Это заставляет NH вставлять сущности, когда они помещаются в сеанс, что приводит к блокировке всей таблицы (в SQL Server).
Сложнее исправить проблему с промывкой. NH должен сбрасывать изменения перед выполнением запросов, чтобы обеспечить согласованность. Вы можете обойти это, установив FlushMode
в Never
, что может вызвать проблемы согласованности, поэтому делайте это только тогда, когда вы точно знаете, что делаете. Лучшее решение - использовать только Get
или Load
или перейти к свойствам корневого объекта вместо выполнения запросов в середине транзакции.
Делая все это, NH может ожидать любую команду Вставить, Обновить и Удалить в базу данных до конца транзакции. Значительно сокращает время блокировки и, следовательно, снижает риск мертвых блокировок.
Общие правила, как избежать тупика
Общие правила, позволяющие избежать взаимоблокировок, также применяются при использовании NHibernate. Самое главное: блокируйте ресурсы в определенном порядке, блокируйте ресурсы не одним, а всеми в начале. Последнее противоречит тому, что я сказал выше, чтобы сократить время блокировки. Это будет означать, что вы блокируете ресурсы в начале транзакции, чтобы другие транзакции ожидали ее завершения. Это может уменьшить взаимоблокировки, но также уменьшает параллельное выполнение.