#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. Спасибо за ответ! Как выясняется, проблемный запрос вызывает исключение, если вы запускаете его напрямую. По какой-то причине он не делает этого в программе, оставляя ее запущенной, но без сеанса.