Sto sviluppando T-SQL da diversi anni e sto approfondendo ulteriormente, continuando a imparare tutto ciò che posso su tutti gli aspetti della lingua. Di recente ho iniziato a lavorare in una nuova società e ho ricevuto quello che penso sia uno strano suggerimento in merito alle transazioni. Non usarli mai. Utilizzare invece una soluzione alternativa che simula una transazione. Questo deriva dal nostro DBA che lavora in un database con molte transazioni e, successivamente, molti blocchi. Il database in cui lavoro principalmente non soffre di questo problema e vedo che le transazioni sono state utilizzate in passato.
Capisco che il blocco è previsto con le transazioni in quanto è nella loro natura farlo e se puoi scappare senza usarne uno, fallo sicuramente. Ma ho molte occasioni in cui ogni istruzione DEVE essere eseguita con successo. Se uno fallisce, tutti non devono impegnarsi.
Ho sempre mantenuto il campo di applicazione delle mie transazioni il più stretto possibile, usato sempre insieme a SET XACT_ABORT ON e sempre all'interno di TRY / CATCH.
Esempio:
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
Ecco cosa mi hanno suggerito di fare.
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
La mia domanda alla comunità è la seguente. Ha senso come soluzione alternativa valida per le transazioni?
La mia opinione da ciò che so sulle transazioni e su ciò che la soluzione propone è che no, questa non è una soluzione praticabile e introduce molti punti di errore.
Nella soluzione alternativa, vedo che si verificano quattro transazioni implicite. I due inserimenti nel tentativo e quindi altre due transazioni per le eliminazioni nel fermo. "Annulla" gli inserti, ma senza eseguire il rollback di nulla, quindi non viene eseguito il rollback di nulla.
Questo è un esempio molto semplice per dimostrare il concetto che stanno suggerendo. Alcune delle effettive procedure memorizzate che ho fatto in questo modo le rendono esaustivamente lunghe e difficili da gestire perché il "rollback" di più set di risultati rispetto a due valori di parametro in questo esempio diventa piuttosto complicato come si può immaginare. Dal momento che il "rollback" è stato fatto manualmente ora, l'opportunità di perdere qualcosa perché reale.
Un altro problema che penso esista è per i timeout o le connessioni interrotte. Viene ancora eseguito il rollback? Questa è la mia comprensione del motivo per cui SET XACT_ABORT ON dovrebbe essere utilizzato in modo che in questi casi la transazione venga ripristinata.
Grazie per il tuo feedback in anticipo!