C'è stato un massiccio aggiornamento per gestire l'errore in SQL Server 2005. Questi articoli sono abbastanza ampia: Error Handling in SQL 2005 and Later by Erland Sommarskog e Error Handling in SQL 2000 – a Background by Erland Sommarskog
Il modo migliore è qualcosa di simile:
Creare la stored procedure come:
CREATE PROCEDURE YourProcedure
AS
BEGIN TRY
BEGIN TRANSACTION --SqlTransaction
DECLARE @ReturnValue int
SET @ReturnValue=NULL
IF (DAY(GETDATE())=1 --logical error
BEGIN
SET @ReturnValue=5
RAISERROR('Error, first day of the month!',16,1) --send control to the BEGIN CATCH block
END
SELECT 1/0 --actual hard error
COMMIT TRANSACTION --SqlTransaction
RETURN 0
END TRY
BEGIN CATCH
IF XACT_STATE()!=0
BEGIN
ROLLBACK TRANSACTION --only rollback if a transaction is in progress
END
--will echo back the complete original error message to the caller
--comment out if not needed
DECLARE @ErrorMessage nvarchar(400), @ErrorNumber int, @ErrorSeverity int, @ErrorState int, @ErrorLine int
SELECT @ErrorMessage = N'Error %d, Line %d, Message: '+ERROR_MESSAGE(),@ErrorNumber = ERROR_NUMBER(),@ErrorSeverity = ERROR_SEVERITY(),@ErrorState = ERROR_STATE(),@ErrorLine = ERROR_LINE()
RAISERROR (@ErrorMessage, @ErrorSeverity, @ErrorState, @ErrorNumber,@ErrorLine)
RETURN ISNULL(@ReturnValue,1)
END CATCH
GO
tuttavia è solo per SQL Server 2005 e versioni successive.Senza utilizzare i blocchi TRY-CATCH in SQL Server 2005, è molto difficile rimuovere tutti i messaggi restituiti da SQL Server. Il extra messages
si riferiscono a sono causati dalla natura di come rollback vengono gestiti utilizzando @@ trancount:
da http://www.sommarskog.se/error-handling-I.html#trancount
@@ TRANCOUNT è una variabile globale che riflette il livello di nidificate transazioni. Ogni BEGIN TRANSAZIONE aumenti @@ trancount da 1, e ogni transazione di commit diminuisce @@ trancount di 1. Nulla è in realtà impegnata fino @@ trancount raggiunge lo 0. ROLLBACK TRANSACTION ripristina tutto al più esterno BEGIN TRANSACTION (a meno che non abbiate utilizzato la transazione SAVE TRANSACTION con esattezza e a 0, per quanto riguarda lo il valore precedente.
quando si esce da una stored procedure, se @@ trancount non ha lo stesso valore come aveva fatto quando la procedura S'inizia esecuzione, SQL Server genera errore 266. Questo errore non è sollevato, però, se la procedura è chiamata da un trigger, direttamente o indirettamente. Né è aumentata se si esegue con il set IMPLICITE OPERAZIONI ON
Se non si desidera ottenere l'avviso sulla transazione conteggio non corrispondono, è necessario disporre di una sola transazione aperta in qualsiasi momento . A tale scopo, la creazione di tutta la vostra procedura come questa:
CREATE PROC YourProcedure
AS
DECLARE @SelfTransaction char(1)
SET @SelfTransaction='N'
IF @@trancount=0
BEGIN
SET @SelfTransaction='Y'
BEGIN TRANSACTION --SqlTransaction
END
SELECT 1/0
IF @@ERROR<> 0
BEGIN
IF @SelfTransaction='Y'
BEGIN
ROLLBACK TRANSACTION --SqlTransaction
END
RETURN -1
END
ELSE
BEGIN
IF @SelfTransaction='Y'
BEGIN
COMMIT TRANSACTION --SqlTransaction
END
RETURN 0
END
GO
In questo modo, si emette comandi solo la transazione se non si è già in una transazione. Se si codificano tutte le procedure in questo modo, solo la procedura o il codice C# che emette la BEGIN TRANSACTION emetterà effettivamente COMMIT/ROLLBACK ei conteggi delle transazioni corrisponderanno sempre (non si otterrà un errore).
in C# da TransactionScope Class Documentation:
static public int CreateTransactionScope(
string connectString1, string connectString2,
string commandText1, string commandText2)
{
// Initialize the return value to zero and create a StringWriter to display results.
int returnValue = 0;
System.IO.StringWriter writer = new System.IO.StringWriter();
try
{
// Create the TransactionScope to execute the commands, guaranteeing
// that both commands can commit or roll back as a single unit of work.
using (TransactionScope scope = new TransactionScope())
{
using (SqlConnection connection1 = new SqlConnection(connectString1))
{
// Opening the connection automatically enlists it in the
// TransactionScope as a lightweight transaction.
connection1.Open();
// Create the SqlCommand object and execute the first command.
SqlCommand command1 = new SqlCommand(commandText1, connection1);
returnValue = command1.ExecuteNonQuery();
writer.WriteLine("Rows to be affected by command1: {0}", returnValue);
// If you get here, this means that command1 succeeded. By nesting
// the using block for connection2 inside that of connection1, you
// conserve server and network resources as connection2 is opened
// only when there is a chance that the transaction can commit.
using (SqlConnection connection2 = new SqlConnection(connectString2))
{
// The transaction is escalated to a full distributed
// transaction when connection2 is opened.
connection2.Open();
// Execute the second command in the second database.
returnValue = 0;
SqlCommand command2 = new SqlCommand(commandText2, connection2);
returnValue = command2.ExecuteNonQuery();
writer.WriteLine("Rows to be affected by command2: {0}", returnValue);
}
}
// The Complete method commits the transaction. If an exception has been thrown,
// Complete is not called and the transaction is rolled back.
scope.Complete();
}
}
catch (TransactionAbortedException ex)
{
writer.WriteLine("TransactionAbortedException Message: {0}", ex.Message);
}
catch (ApplicationException ex)
{
writer.WriteLine("ApplicationException Message: {0}", ex.Message);
}
// Display messages.
Console.WriteLine(writer.ToString());
return returnValue;
}
Solo un pensiero, ma si potrebbe essere in grado di utilizzare il TransactionAbortedException
cattura per ottenere l'errore effettivo e ignorare l'avviso mancata corrispondenza conteggio delle transazioni.
@KM, hai 'IF @@ trancount <0' all'inizio del processo di esempio. Il trancount @@ può mai essere negativo? Non dovrebbe essere "IF @@ trancount = 0' ?? –
@Charles Bretana, hai ragione, è un tipo-o. Lo aggiusterò ... –
@KM, Thx! ha funzionato nel mio test sproc con il cambiamento, ma questo è stato qui indisturbato da aprile/maggio ... Quindi il mio presupposto naturale è che mi manca qualcosa ... Non ero completamente sicuro in un modo o nell'altro ... Felice Vacanze ! –