He estado desarrollando T-SQL durante varios años y siempre estoy investigando más, continuando aprendiendo todo lo que puedo sobre todos los aspectos del lenguaje. Recientemente comencé a trabajar en una nueva empresa y he recibido lo que creo que es una sugerencia extraña con respecto a las transacciones. Nunca los uses. En su lugar, use una solución alternativa que simule una transacción. Esto proviene de nuestro DBA que trabaja en una base de datos con muchas transacciones y, posteriormente, muchos bloqueos. La base de datos en la que trabajo principalmente no sufre este problema y veo que las transacciones se han utilizado en el pasado.
Entiendo que se espera el bloqueo con las transacciones, ya que está en su naturaleza hacerlo y si puede escapar sin usar una, hágalo de todas maneras. Pero tengo muchas ocasiones donde cada declaración DEBE ejecutarse con éxito. Si uno falla, todos deben dejar de comprometerse.
Siempre mantuve el alcance de mis transacciones lo más estrecho posible, siempre lo utilicé junto con SET XACT_ABORT ON y siempre dentro de TRY / CATCH.
Ejemplo:
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
Esto es lo que me sugirieron que haga.
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
Mi pregunta a la comunidad es la siguiente. ¿Tiene sentido esto como una solución viable para las transacciones?
Mi opinión sobre lo que sé sobre las transacciones y lo que propone la solución es que no, esta no es una solución viable e introduce muchos puntos de falla.
En la solución sugerida, veo que ocurren cuatro transacciones implícitas. Las dos inserciones en el intento y luego dos transacciones más para las eliminaciones en la captura. Hace "deshacer" las inserciones, pero sin deshacer nada, por lo que nada se revierte.
Este es un ejemplo muy básico para demostrar el concepto que sugieren. Algunos de los procedimientos almacenados reales en los que he estado haciendo esto los hacen exhaustivamente largos y difíciles de administrar porque "revertir" múltiples conjuntos de resultados frente a dos valores de parámetros en este ejemplo se vuelve bastante complicado como se podría imaginar. Como "retroceder" se está haciendo manualmente ahora, la oportunidad de perder algo porque es real.
Otro problema que creo que existe es por tiempos de espera o conexiones cortadas. ¿Esto todavía se revierte? Esta es mi comprensión de por qué SET XACT_ABORT ON debe usarse para que, en estos casos, la transacción retroceda.
Gracias por sus comentarios de antemano!