Я занимаюсь разработкой T-SQL в течение нескольких лет и постоянно копаюсь, продолжая изучать все, что могу, по всем аспектам языка. Недавно я начал работать в новой компании и получил, как мне кажется, странное предложение относительно транзакций. Никогда не используйте их. Вместо этого используйте обходной путь, имитирующий транзакцию. Это исходит от нашего администратора базы данных, который работает в одной базе данных с большим количеством транзакций и, следовательно, с большим количеством блокировок. База данных, в которой я в основном работаю, не страдает от этой проблемы, и я вижу, что транзакции использовались в прошлом.
Я понимаю, что блокирование ожидается с транзакциями, так как это по своей природе это сделать, и если вы можете уйти, не используя одну, обязательно сделайте это. Но у меня есть много случаев, когда каждое утверждение ДОЛЖНО выполняться успешно. Если кто-то терпит неудачу, они все должны потерпеть неудачу.
Я всегда держал область своих транзакций как можно более узкой, всегда используемой вместе с SET XACT_ABORT ON и всегда в пределах TRY / CATCH.
Пример:
CREATE SCHEMA someschema;
GO
CREATE TABLE someschema.tableA
(id INT NOT NULL IDENTITY(1, 1) PRIMARY KEY,
ColA VARCHAR(10) NOT NULL
);
GO
CREATE TABLE someschema.tableB
(id INT NOT NULL IDENTITY(1, 1) PRIMARY KEY,
ColB VARCHAR(10) NOT NULL
);
GO
CREATE PROCEDURE someschema.ProcedureName @ColA VARCHAR(10),
@ColB VARCHAR(10)
AS
SET NOCOUNT, XACT_ABORT ON;
BEGIN
BEGIN TRY
BEGIN TRANSACTION;
INSERT INTO someschema.tableA(ColA)
VALUES(@ColA);
INSERT INTO someschema.tableB(ColB)
VALUES(@ColB);
--Implement error
SELECT 1/0
COMMIT TRANSACTION;
END TRY
BEGIN CATCH
IF @@trancount > 0
BEGIN
ROLLBACK TRANSACTION;
END;
THROW;
RETURN;
END CATCH;
END;
GO
Вот что они предложили мне сделать.
GO
CREATE PROCEDURE someschema.ProcedureNameNoTransaction @ColA VARCHAR(10),
@ColB VARCHAR(10)
AS
SET NOCOUNT ON;
BEGIN
BEGIN TRY
DECLARE @tableAid INT;
DECLARE @tableBid INT;
INSERT INTO someschema.tableA(ColA)
VALUES(@ColA);
SET @tableAid = SCOPE_IDENTITY();
INSERT INTO someschema.tableB(ColB)
VALUES(@ColB);
SET @tableBid = SCOPE_IDENTITY();
--Implement error
SELECT 1/0
END TRY
BEGIN CATCH
DELETE FROM someschema.tableA
WHERE id = @tableAid;
DELETE FROM someschema.tableB
WHERE id = @tableBid;
THROW;
RETURN;
END CATCH;
END;
GO
Мой вопрос к сообществу заключается в следующем. Имеет ли это смысл в качестве жизнеспособного обходного пути для транзакций?
Мое мнение о том, что я знаю о транзакциях и о том, что предлагает решение, состоит в том, что нет, это не является жизнеспособным решением и создает много точек отказа.
В предлагаемом обходном пути я вижу четыре неявных транзакции. Две вставки в попытке, а затем еще две транзакции для удалений в перехвате. Он «отменяет» вставки, но без отката ничего, так что на самом деле ничего не откатывается.
Это очень простой пример, чтобы продемонстрировать концепцию, которую они предлагают. Некоторые из реальных хранимых процедур, в которых я делал это, делают их чрезвычайно длинными и сложными в управлении, поскольку «откат» нескольких наборов результатов по сравнению с двумя значениями параметров в этом примере становится довольно сложным, как вы могли себе представить. Поскольку «откат» сейчас делается вручную, появилась возможность что-то упустить, потому что реально.
Другая проблема, которая, я думаю, существует, связана с таймаутами или разрывом соединений. Это все еще откатывается? Это мое понимание того, почему следует использовать SET XACT_ABORT ON, чтобы в этих случаях транзакция откатывалась.
Спасибо за ваш отзыв заранее!