Accesso 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 in modo esplicito alla transazione. 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 desidera integrare una risorsa che non esegue l'integrazione automatica o che per qualche motivo non è stata integrata 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. Nel codice seguente, ad esempio, viene eseguito il rollback della transazione corrente:
using(TransactionScope transactionScope = new TransactionScope(TransactionScopeOptions.Required)) { }
Nella parte restante di questo argomento vengono descritte altre modalità di annullamento di una transazione esterna.
Annullamento di 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 o la funzione gestita può annullare la transazione corrente chiamando il metodo Transaction.Rollback se viene soddisfatta una determinata condizione.
Quando viene chiamato all'interno di una routine o di una funzione gestita, il metodo Transaction.Rollback 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 al 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 verrà generata immediatamente alla routine Transact-SQL chiamante e l'esecuzione del codice gestito verrà completata. 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
Di seguito è riportato un esempio di 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. Tenere presente che 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();
}
}
};
Imports System
Imports System.Data
Imports System.Data.SqlClient
Imports System.Data.SqlTypes
Imports Microsoft.SqlServer.Server
Imports System.Transactions
Partial Public Class StoredProcedures
<Microsoft.SqlServer.Server.SqlProcedure()> _
Public Shared Sub uspRollbackFromProc ()
Using connection As New SqlConnection("context connection=true")
' Open the connection.
connection.Open()
Dim successCondition As Boolean
successCondition = False
' Success condition is met.
If successCondition Then
SqlContext.Pipe.Send("Success condition met in procedure.")
' 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.
Dim trans As Transaction
trans = Transaction.Current
trans.Rollback()
Catch ex As SqlException
' Catch the exception instead of throwing it.
' This allows the connection to close correctly.
End Try
End If
' Close the connection.
connection.Close()
End Using
End Sub
End Class
Transact-SQL
--Register assembly.
CREATE ASSEMBLY TestProcs FROM 'C:\Programming\TestProcs.dll'
Go
CREATE PROCEDURE uspRollbackFromProc AS EXTERNAL NAME TestProcs.StoredProcedures.uspRollbackFromProc
Go
-- Execute procedure.
BEGIN TRY
BEGIN TRANSACTION
-- Perform other actions.
Exec 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 TRANSACTION
PRINT N'Transaction rolled back.'
END CATCH
Go
-- Clean up.
DROP Procedure uspRollbackFromProc;
Go
DROP ASSEMBLY TestProcs;
Go