Ошибка NHibernate IStatelessSession CreateQuery

Когда мы выпустили в прошлую пятницу, я получил ошибку, которую я не получаю при принятии. Сообщение об ошибке:

could not execute update query[SQL: delete from dbo.MyTable where col1=? and col2=? and col3=? and col4=? and col5=?]

Мой код C# выглядит следующим образом:

var hqlDelete = "DELETE MyTable m WHERE m.Col1 = :var_1 AND m.Col2 = :var_2 AND m.Col3= :var_3 AND m.Col4 = :var_4 AND m.Col5= :var_5";
var deletedEntities = session.CreateQuery(hqlDelete)
                             .SetString("var_1", variable1)
                             .SetString("var_2", variable2)
                             .SetString("var_3", variable3)
                             .SetString("var_4", variable4)
                             .SetString("var_5", variable5)
                             .ExecuteUpdate();
transaction.Commit();
session.Close();

Теперь, как я уже сказал, ошибка не сработала при тестировании на приемку. Кроме того, когда я тестирую с производственной базой данных (код из моего места разработчика), это тоже работает без проблем.

Код срабатывает, когда я называю веб-сервис и отправляю в него "измерение". Разница лишь в том, что я вызываю сервис при тестировании, а на производстве другая компания отправляет измерения в веб-сервис.

Я думаю, что это может быть связано с количеством сеансов / транзакций, но это не объясняет, почему переменные отображаются как ? в сообщении об ошибке.

Есть идеи? Могу ли я предоставить больше информации, чтобы вы могли помочь мне с этим?

Изменить: InnerExeption является

{"Transaction (Process ID 68) was deadlocked on lock | communication buffer resources with another process and has been chosen as the deadlock victim. Rerun the transaction."}

1 ответ

Решение

Устранение тупиковых ситуаций может быть трудной задачей, особенно при использовании ORM. Как правило, взаимоблокировки возникают из-за того, что блокировки объектов базы данных не создаются в одном и том же порядке разными процессами (или потоками), заставляя их ждать друг друга.

ORM не дает вам большого контроля над порядком получения блокировки. Вы можете изменить порядок запросов, но это может быть утомительным. Особенно, когда кеширование приводит к тому, что некоторые из них не попадают в БД. Более того, это должно быть сделано с тем же порядком в любом другом приложении, использующем ту же базу данных.

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

Если вашей базой данных является SQL Server, существует настройка по умолчанию, которая значительно увеличивает риск взаимоблокировок: отключение режима моментального снимка для чтения. Если он отключен в вашей базе данных, вы можете значительно снизить риски взаимоблокировки, включив его. Этот режим позволяет выполнять чтение при уровне изоляции для фиксации чтения и прекращать выдачу блокировок чтения.

Вы можете проверить эту настройку с

select snapshot_isolation_state_desc, is_read_committed_snapshot_on
    from sys.databases 
    where name = 'YourDbName'

Вы можете включить эту настройку с

alter database YourDbName
    set allow_snapshot_isolation on

alter database YourDbName
    set read_committed_snapshot on

Это требует отсутствия запущенной транзакции на целевой базе данных. И конечно, для этого требуются права администратора БД.

В приложении, для которого у меня не было возможности изменить этот параметр, мне пришлось пойти более странным путем: установить режим изоляции NHibernate по умолчанию (connection.isolation параметр конфигурации) для ReadUncommitted, Мое приложение было в основном только для чтения, и я явно повышал режим изоляции для нескольких транзакций, которые должны были читать, а затем записывать данные (используя session.BeginTransaction(System.Data.IsolationLevel.ReadCommitted) по примеру).

Вам также следует проверить режимы изоляции, которые в настоящее время используются всеми приложениями, использующими базу данных: некоторые из них используют более высокий уровень изоляции, чем фактически требуется? (RepeatableRead а также Serializable следует избегать, если это возможно.) Это трудоемкий процесс, так как он требует хорошего понимания уровней изоляции при изучении каждого варианта использования для определения того, что является подходящим минимальным уровнем изоляции.

Другие вопросы по тегам