Какая директива в базе данных влияет на поведение транзакций при ошибках
Что проверяют
Знаете ли вы, что в SQL Server ошибка внутри транзакции по умолчанию не откатывает её целиком. Речь о SET XACT_ABORT. Следом спрашивают, как это стыкуется с TRY...CATCH и что будет при таймауте команды из C#.
Как отвечать
- по умолчанию
XACT_ABORT OFF: многие ошибки выполнения, например дубль по уникальному ключу или нарушение внешнего ключа, откатывают только упавшую инструкцию. Транзакция живёт дальше, иCOMMITзафиксирует половину изменений; - при
SET XACT_ABORT ON: ошибка выполнения прерывает батч и откатывает всю транзакцию. Ошибки компиляции, например синтаксис, настройка не затрагивает; - вместе с
TRY...CATCH: приONтранзакция вCATCHстановится нефиксируемой,XACT_STATE()возвращает-1, выход один:ROLLBACK. Каркас процедуры:SET XACT_ABORT ON,BEGIN TRY,BEGIN TRAN, работа,COMMIT; вCATCHпроверкаIF @@TRANCOUNT > 0 ROLLBACKиTHROW; THROWиRAISERROR: первый учитываетXACT_ABORT, второй нет;- таймауты из C#: по истечении
CommandTimeout(по умолчанию 30 секунд) клиент отменяет команду, сервер прерывает батч, но приOFFоткрытая транзакция остаётся и держит блокировки, пока соединение не закроют или не переиспользуют из пула. ПоэтомуXACT_ABORT ONв процедурах считают хорошей практикой.
В .NET транзакцию ведут через SqlTransaction, TransactionScope или Database.BeginTransaction() в EF Core. Dispose без Commit откатывает её, поэтому оборачивайте в using.
Для контраста: в PostgreSQL после любой ошибки транзакция считается прерванной, и до ROLLBACK или отката к точке сохранения команды игнорируются.
Где спотыкаются
Считают, что без XACT_ABORT ошибка сама откатит транзакцию. Итог: частично записанные данные после «успешного» COMMIT.
Думают, что ON отменяет нужду в TRY...CATCH. Логирование и понятная ошибка для клиента всё равно нужны.
Путают настройку с уровнем изоляции. READ COMMITTED или SNAPSHOT отвечают за видимость данных, а не за реакцию на ошибки.