Почему моя транзакция автоматически откатывается при сбое INSERT INTO? - PullRequest
3 голосов
/ 17 апреля 2019

Удивительно, но я не смог найти подходящего объяснения или документации по этой проблеме, с которой я столкнулся.

В случае этих операторов SQL:

SELECT 1 AS Test INTO #tmpTest    
BEGIN TRAN    
SELECT 1 AS Test INTO #tmpTest    
ROLLBACK TRAN

При выполнении одного за другим SELECT ... INTO в строке 3 завершается неудачно, как и ожидалось, с сообщением -

В базе данных уже есть объект с именем #tmpTest.

Однако после этого оператор ROLLBACK в строке 4 завершается ошибкой:

У запроса ROLLBACK TRANSACTION нет соответствующего BEGIN СДЕЛКИ.

Несмотря на то, что транзакция успешно BEGIN была успешно выполнена в строке 2.

Я видел SQL Server - транзакции откатываются при ошибке? , но ответы здесь не применяются, потому что по умолчанию xact_abort равно off. Кроме того, ответ от Quassnoi противоречит ответу от Raj More .

Какое фактическое объяснение?

Ответы [ 2 ]

3 голосов
/ 18 апреля 2019

См. http://www.sommarskog.se/error-handling-I.html

В данном случае вы получаете групповой аборт, который приводит к неявному откату. Блог посвящен обработке ошибок SQL Server 2000, но большинство из них по-прежнему остаются действительными.

Edit: немного больше копать и нашел это, в котором конкретно упоминается случай создания таблицы, которая уже существует: http://www.sommarskog.se/error_handling/Part2.html#BatchTranAbort

2 голосов
/ 18 апреля 2019

Согласно этой статье Microsoft: XACT_STATE (Transact-SQL)

(...) произошла ошибка, в результате которой была классифицирована транзакция как незафиксированная транзакция. Запрос не может зафиксировать транзакция или откат к точке сохранения; он может запросить только полный откат транзакции.

Я запускаю это первым:

SELECT 1 AS Test INTO #tmpTest    
SELECT @@TRANCOUNT, XACT_STATE()
BEGIN TRAN    
SELECT @@TRANCOUNT, XACT_STATE()

Тогда:

BEGIN TRY
    SELECT 1 AS Test INTO #tmpTest    
END TRY
BEGIN CATCH
    SELECT @@ERROR, ERROR_MESSAGE()
    SELECT @@TRANCOUNT, XACT_STATE()
END CATCH

Возвращено SELECT в блоке CATCH: " В базе данных уже есть объект с именем" #tmpTest ". ", @@TRANCOUNT - это 1, но XACT_STATE -1, поэтому сообщение об ошибке в SSMS гласит:

Сообщение 3998, уровень 16, состояние 1, строка 1 Нефиксированная транзакция обнаружен в конце партии. Откат транзакции.

Следующее SELECT @@TRANCOUNT возвращает 0.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...