Accedere alla transazione corrente
Si applica a:SQL Server
Se una transazione è attiva nel punto in cui viene immesso il codice CLR (Common Language Runtime) in esecuzione in SQL Server, la transazione viene esposta tramite la classe System.Transactions.Transaction
. La proprietà Transaction.Current
viene utilizzata per accedere alla transazione corrente. Nella maggior parte dei casi, non è necessario accedere alla transazione in modo esplicito. Per le connessioni al database, ADO.NET controlla automaticamente Transaction.Current
quando viene chiamato il metodo Connection.Open
e integra in modo trasparente la connessione in tale transazione ,a meno che la parola chiave Enlist
non sia impostata su false nella stringa di connessione.
È possibile usare l'oggetto Transaction
direttamente negli scenari seguenti:
Se si vuole integrare una risorsa che non esegue l'integrazione automatica o che per qualche motivo non è stata inserita durante l'inizializzazione.
Se si desidera integrare in modo esplicito una risorsa nella transazione.
Se si desidera terminare la transazione esterna dalla stored procedure o dalla funzione. In questo caso, utilizzare TransactionScope. Ad esempio, il codice seguente esegue il rollback della transazione corrente:
using(TransactionScope transactionScope = new TransactionScope(TransactionScopeOptions.Required)) { }
Il resto di questo articolo descrive altri modi per annullare una transazione esterna.
Annullare una transazione esterna
È possibile annullare le transazioni esterne da una funzione o procedura gestita nelle modalità seguenti:
La funzione o procedura gestita può restituire un valore utilizzando un parametro di output. La routine Transact-SQL chiamante può controllare il valore restituito e, se appropriato, eseguire
ROLLBACK TRANSACTION
.La funzione o procedura gestita può generare un'eccezione personalizzata. La routine Transact-SQL chiamante può intercettare l'eccezione generata dalla routine o dalla funzione gestita in un blocco try/catch ed eseguire
ROLLBACK TRANSACTION
.La routine gestita o la funzione può annullare la transazione corrente chiamando il metodo
Transaction.Rollback
se viene soddisfatta una determinata condizione.
Quando il metodo Transaction.Rollback
viene chiamato all'interno di una routine o di una funzione gestita, genera un'eccezione con un messaggio di errore ambiguo e può essere eseguito il wrapping in un blocco try/catch. Il messaggio di errore è simile all'output seguente:
Msg 3994, Level 16, State 1, Procedure uspRollbackFromProc, Line 0
Transaction is not allowed to roll back inside a user defined routine, trigger or aggregate because the transaction is not started in that CLR level. Change application logic to enforce strict transaction nesting.
Questa eccezione è prevista e il blocco try/catch è necessario per continuare a eseguire il codice. Senza il blocco try/catch, l'eccezione viene generata immediatamente alla routine chiamante Transact-SQL e l'esecuzione del codice gestito termina. Al termine dell'esecuzione del codice gestito, viene generata un'altra eccezione:
Msg 3991, Level 16, State 1, Procedure uspRollbackFromProc, Line 1
The context transaction which was active before entering user defined routine, trigger or aggregate " uspRollbackFromProc " has been ended inside of it, which is not allowed. Change application logic to enforce strict transaction nesting. The statement has been terminated.
Questa eccezione è prevista e, per continuare l'esecuzione, è necessario disporre di un blocco try/catch intorno all'istruzione Transact-SQL che esegue l'azione che attiva il trigger. Nonostante le due eccezioni generate, viene eseguito il rollback della transazione e le modifiche non vengono sottoposte a commit.
Esempio
Il codice seguente è un esempio di una transazione di cui viene eseguito il rollback da una routine gestita usando il metodo Transaction.Rollback
. Si noti il blocco try/catch intorno al metodo Transaction.Rollback
nel codice gestito. Lo script Transact-SQL crea un assembly e una stored procedure gestita. L'istruzione EXEC uspRollbackFromProc
viene sottoposta a wrapping in un blocco try/catch, in modo che l'eccezione generata quando la routine gestita completa l'esecuzione viene intercettata.
using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
using System.Transactions;
public partial class StoredProcedures
{
[Microsoft.SqlServer.Server.SqlProcedure]
public static void uspRollbackFromProc()
{
using (SqlConnection connection = new SqlConnection(@"context connection=true"))
{
// Open the connection.
connection.Open();
bool successCondition = true;
// Success condition is met.
if (successCondition)
{
SqlContext.Pipe.Send("Success condition met in procedure.");
// Perform other actions here.
}
// Success condition is not met, the transaction will be rolled back.
else
{
SqlContext.Pipe.Send("Success condition not met in managed procedure. Transaction rolling back...");
try
{
// Get the current transaction and roll it back.
Transaction trans = Transaction.Current;
trans.Rollback();
}
catch (SqlException ex)
{
// Catch the expected exception.
// This allows the connection to close correctly.
}
}
// Close the connection.
connection.Close();
}
}
};
Registrare ed eseguire l'assembly in Transact-SQL
Registrare l'assembly.
CREATE ASSEMBLY TestProcs FROM 'C:\Programming\TestProcs.dll'; GO CREATE PROCEDURE uspRollbackFromProc AS EXTERNAL NAME TestProcs.StoredProcedures.uspRollbackFromProc; GO
Eseguire la procedura.
BEGIN TRY BEGIN TRANSACTION; -- Perform other actions. EXECUTE uspRollbackFromProc; -- Perform other actions. PRINT N'Commiting transaction...'; COMMIT TRANSACTION; END TRY BEGIN CATCH SELECT ERROR_NUMBER() AS ErrorNum, ERROR_MESSAGE() AS ErrorMessage; PRINT N'Exception thrown, rolling back transaction.'; ROLLBACK; PRINT N'Transaction rolled back.'; END CATCH GO
Pulire l'ambiente.
DROP PROCEDURE uspRollbackFromProc; GO DROP ASSEMBLY TestProcs; GO