SQL Server автоматически удаляет транзакцию после запроса

#sql #sql-server #transactions

#sql #sql-server #транзакции

Вопрос:

Версия SQL Server 14.0.1000.169.

Я запускаю транзакцию, выполняю список запросов, но при попытке выполнить commit я получил сообщение об ошибке 20018 The COMMIT TRANSACTION request has no corresponding BEGIN TRANSACTION . До этого не было ошибок, и соединение не разрывается.

Итак, я попытался регистрировать каждый запрос DML, выполняя SELECT XACT_STATE(), @@TRANCOUNT до и после каждого выполнения, вот что я получил:

     [XACT_STATE()] => 0
    [@@TRANCOUNT] => 0
-----------------------
BEGIN TRAN
-----------------------
    [XACT_STATE()] => 1
    [@@TRANCOUNT] => 1
-----------------------
<<<Skipped several queries that do no cause the issue>>>
-----------------------
    [XACT_STATE()] => 1
    [@@TRANCOUNT] => 1
-----------------------
SELECT unpvt.productID AS ProductID,
       t.[Index] AS ImageSequence,
       unpvt.Image AS ImageFileName
INTO #tempImages
FROM (
         SELECT *
         FROM tProductNewImport pi
         WHERE pi.ProductNewImportInstanceID = :ProductNewImportInstanceID
           AND pi.deleted IS NULL
           AND pi.productID IS NOT NULL
           AND pi.StoreID = :StoreID
     ) pi
         UNPIVOT (Image FOR [Column] IN (f6)) unpvt
         JOIN (VALUES (1, 'f6')) t ([Index], [Column])
              ON t.[Column] = unpvt.[Column];

CREATE UNIQUE NONCLUSTERED INDEX [NonClusteredIndex-c3975d93e8521] ON [dbo].[#tempImages]
(
    [ProductID] ASC,
    [ImageFileName] ASC
);



DELETE tpi FROM dbo.tProductImage tpi
JOIN #tempImages i on tpi.ProductID = i.ProductID
WHERE tpi.StoreID = :StoreID
AND NOT EXISTS (SELECT * FROM #tempImages i2 WHERE tpi.ProductID = i2.ProductID and tpi.ImageFileName = i2.ImageFileName);


UPDATE tpi
SET ImageSequence = i.ImageSequence * 10
FROM dbo.tProductImage tpi
JOIN #tempImages i on tpi.ProductID = i.ProductID and tpi.ImageFileName = i.ImageFileName
WHERE tpi.StoreID = :StoreID;


INSERT INTO tProductImage (StoreID, ProductID, ImageSequence, ImageFileName)
SELECT :StoreID, i.ProductID, i.ImageSequence * 10, i.ImageFileName
FROM #tempImages i
WHERE NOT EXISTS (SELECT * FROM dbo.tProductImage tpi WHERE tpi.StoreID=:StoreID AND tpi.ProductID=i.ProductID AND tpi.ImageFileName=i.ImageFileName);
-----------------------
    [XACT_STATE()] => 0
    [@@TRANCOUNT] => 0
  

Последний — это один запрос с несколькими операторами в нем.
После этого транзакция исчезла без каких-либо явных инструкций «завершить транзакцию».
Я только предполагаю, что команда ‘create index’ каким-то образом выполняет фиксацию, но я не смог найти никакой информации об этом.

Комментарии:

1. sql server не удаляет транзакции автоматически. у вас ошибка в вашем коде….

Ответ №1:

Вместо этого используйте следующий шаблон:

 SET NOCOUNT, XACT_ABORT ON;

BEGIN TRY;
            
    BEGIN TRANSACTION;

    --

        /* your code goes here */

    --

    COMMIT TRANSACTION;

END TRY
BEGIN CATCH

    IF @@TRANCOUNT > 0
    BEGIN;
        ROLLBACK TRANSACTION;
    END;

    THROW;

END CATCH;

SET NOCOUNT, XACT_ABORT OFF;
  

Создание индекса не влияет на @@TRANCOUNT как:

Оператор BEGIN TRANSACTION увеличивает @@TRANCOUNT на 1. ТРАНЗАКЦИЯ ОТКАТА уменьшает @@TRANCOUNT до 0, за исключением ТРАНЗАКЦИИ ОТКАТА savepoint_name, которая не влияет на @@TRANCOUNT . ЗАФИКСИРУЙТЕ ТРАНЗАКЦИЮ или ЗАФИКСИРУЙТЕ РАБОТУ, уменьшите @@TRANCOUNT на 1.

Я не уверен, как вы выполняете свой код и почему ошибка не возвращается. Если вы прокомментируете index creation и ошибка исчезнет, возможно, у вас дублированные значения, и вы пытаетесь создать уникальный индекс.

Используйте шаблон и дайте мне знать, каков результат.

Комментарии:

1. Спасибо за ответ! Как выясняется, проблемный запрос вызывает исключение, если вы запускаете его напрямую. По какой-то причине он не делает этого в программе, оставляя ее запущенной, но без сеанса.