У меня есть несколько долго выполняющихся команд в хранимых процедурах, которые подвергаются риску истечения времени ожидания, и я запускаю их, используя Context.Database.ExecuteSqlCommand
Может показаться, что когда команда истекает, она оставляет блокировку вбазы данных, потому что транзакция не откатывается.
Я нашел объяснение этому здесь: CommandTimeout - как правильно его обрабатывать?
На основе связанных пример Я изменил свой код на:
Database database = Context.Database;
try
{
return database.ExecuteSqlCommand(sql, parameters);
}
catch (SqlException e)
{
//Transactions can stay open after a CommandTimeout,
//so need to rollback any open transactions
if (e.Number == -2) //CommandTimeout occurred
{
//Single rollback exits all levels of nested transactions,
//no need to loop.
database.ExecuteSqlCommand("IF @@TRANCOUNT>0 ROLLBACK TRAN;");
}
throw;
}
Однако это вызвало исключение внутри перехвата, потому что соединение теперь пустое:
ArgumentNullException: Value cannot be null.
Parameter name: connection
После комментариев от Эннии usr я изменил свой код на это:
Database database = Context.Database;
using (var tran = database.BeginTransaction())
{
try
{
int result = database.ExecuteSqlCommand(sql, parameters);
tran.Commit();
return result;
}
catch (SqlException)
{
var debug = database.SqlQuery<Int16>("SELECT @@SPID");
tran.Rollback();
throw;
}
}
Я действительно думал, что это будет делать, но блокировки в базе данных продолжают накапливаться, когда я устанавливаю для CommandTimeout
действительно маленькое значение, чтобы проверить егоиз.
Я поставил точку останова на броске, так что я знаю, что транзакция была отменена.Переменная debug сообщает мне идентификатор сеанса, и когда я проверяю свои блокировки, используя этот запрос: SELECT * FROM sys.dm_tran_locks
, я нахожу совпадение для идентификатора сеанса в request_session_id
, но это уже была блокировка, а не одна из новыхте, так что я немного запутался.
Итак, как мне правильно обрабатывать CommandTimeout
при использовании ExecuteSqlCommand
, чтобы гарантировать немедленное снятие блокировок?
Я скачал sp_whoisactive
изапустив его, spid, кажется, связан с запросом к таблицам, используемым Hangfire - я использую Hangfire для запуска длительных запросов в фоновом процессе.Итак, я думаю, что, возможно, я лаю не на том дереве.У меня действительно была проблема с блокировкой, но я переписал свои собственные запросы, чтобы избежать блокировки слишком большого количества строк, и я отключил повышение блокировки для таблиц, где у меня возникла проблема.Эти последние блокировки могут исходить от Hangfire, и они могут быть несущественными, тем не менее, я решил пока использовать XACT_ABORT ON
.