Rozwijam T-SQL od kilku lat i zawsze zagłębiam się dalej, wciąż ucząc się wszystkiego, co mogę, o wszystkich aspektach języka. Niedawno zacząłem pracować w nowej firmie i otrzymałem dziwną sugestię dotyczącą transakcji. Nigdy ich nie używaj. Zamiast tego użyj obejścia, które symuluje transakcję. To pochodzi od naszego DBA, który pracuje w jednej bazie danych z dużą ilością transakcji, a następnie z dużą ilością blokowania. Baza danych, w której przede wszystkim pracuję, nie ma tego problemu i widzę, że transakcje były używane w przeszłości.
Rozumiem, że oczekuje się blokowania transakcji, ponieważ jest to w ich naturze i jeśli możesz uciec bez korzystania z nich, zrób to. Ale mam wiele okazji, w których każda instrukcja MUSI zostać wykonana pomyślnie. Jeśli ktoś zawiedzie, wszyscy muszą się nie popełnić.
Zawsze utrzymywałem jak najmniejszy zakres moich transakcji, zawsze używany w połączeniu z SET XACT_ABORT ON i zawsze w ramach TRY / CATCH.
Przykład:
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
Oto, co zasugerowali mi zrobić.
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
Moje pytanie do społeczności jest następujące. Czy ma to sens jako praktyczne obejście transakcji?
Moim zdaniem z tego, co wiem o transakcjach i propozycji rozwiązania, jest to, że nie, nie jest to realne rozwiązanie i wprowadza wiele punktów niepowodzenia.
W sugerowanym obejściu widzę cztery niejawne transakcje. Dwie wstawki w try, a następnie dwie kolejne transakcje usuwania w catch. Robi to „cofanie” wkładek, ale bez cofania niczego, więc nic nie jest cofane.
Jest to bardzo podstawowy przykład, aby zademonstrować proponowaną przez siebie koncepcję. Niektóre z rzeczywistych procedur przechowywanych, w których to robię, sprawiają, że są one wyjątkowo długie i trudne do zarządzania, ponieważ „wycofywanie” wielu zestawów wyników w porównaniu z dwoma wartościami parametrów w tym przykładzie staje się dość skomplikowane, jak można sobie wyobrazić. Ponieważ „wycofywanie” odbywa się teraz ręcznie, możliwość przegapienia czegoś, ponieważ jest realna.
Innym problemem, który moim zdaniem istnieje, są przekroczenia limitu czasu lub zerwane połączenia. Czy to wciąż się wycofuje? Rozumiem, dlaczego należy użyć SET XACT_ABORT ON, aby w takich przypadkach transakcja została wycofana.
Z góry dziękuję za opinię!