Reputation: 4229
I have a SQL Server 2008 R2 stored procedure that runs a few INSERTs and UPDATEs in a TRANSACTION. After each statement, I need to log what just happened before doing the next step.
Here is my code:
BEGIN TRY
BEGIN TRANSACTION
INSERT INTO... -- 1st statement
INSERT INTO MyEventLog (EventDescription) VALUES ('Did Step 1') -- log
UPDATE... -- 2nd statement
INSERT INTO MyEventLog (EventDescription) VALUES ('Did Step 2') -- log
COMMIT TRANSACTION
END TRY
BEGIN CATCH
IF (@@TRANCOUNT<>0) ROLLBACK TRANSACTION
EXEC LogError 'I got an error'
END CATCH
Problem is: if there is an error, the transaction rolls back all statements -- including the logging which I need. in the event of an error, how do I roll back the transactions but keep the logging.
Upvotes: 3
Views: 831
Reputation: 32687
As it turns out, table variables don't obey transaction semantics. So, you could insert into a table variable and then insert from your table variable into your logging table after the catch block.
Upvotes: 0
Reputation: 294217
See Logging messages during a transaction. Is a bit convoluted:
But it does allow you to log messages during a transaction and the messages will be persisted even if the transaction rolls back. Order of logging is preserved.
You also need to make your transaction and stored procedure play nice when one procedure fails but the transaction can continue (eg. when processing a batch and one item fails, you want to continue wit the rest of the batch). See Exception handling and nested transactions.
Upvotes: 1
Reputation: 1653
How about putting the logging statements into a separate transaction?
I'd put it down in the CATCH block:
BEGIN CATCH
IF (@@TRANCOUNT<>0)
ROLLBACK TRANSACTION
EXEC LogError 'I got an error'
BEGIN TRANSACTION
INSERT INTO MyEventLog (EventDescription) VALUES ('Error Updating') -- log
END TRANSACTION
END CATCH
Upvotes: 0
Reputation: 1325
I was going to ask why you would want to log an event that technically didn't happen, since the transaction would have been rolled back and the database would be in the state it was in before the transaction. But then it occurred to me that you probably just want to log it in order to know WHERE it failed so you can fix the underlying issue, which is a smart thing to do.
If that is indeed the case, the best thing to do is to rollback the entire transaction as you are currently doing, and to use your LogError SP to log the error message in another table. This is what I use:
CREATE PROCEDURE [dbo].[Error_Handler]
@returnMessage bit = 'False'
WITH EXEC AS CALLER
AS
BEGIN
DECLARE @number int,
@severity int,
@state int,
@procedure varchar(100),
@line int,
@message varchar(4000)
INSERT INTO Errors (Number,Severity,State,[Procedure],Line,[Message])
VALUES (
ERROR_NUMBER(),
ERROR_SEVERITY(),
ERROR_STATE(),
isnull(ERROR_PROCEDURE(),'Ad-Hoc Query'),
isnull(ERROR_LINE(),0),
ERROR_MESSAGE())
IF(@returnMessage = 'True')
BEGIN
select *
from Errors
where ErrorID = scope_identity()
END
END
The error message should let you know what went wrong in what table, and that should be enough info to fix the problem.
Upvotes: 1