when i try to run an insert within an application, it hangs and eventually times out.
i ran the EXEC SP_WHO2 while it was still running and noticed that it was blocked by another process and there was a "lock" in the "wait type"
what does this mean? how do i fix it? i'm so lost.
the process that was in the "Blocked By" field had a delete statement in it. i validated the statement and it works fine.
Seems like your previous transaction is in open state due to some error in your stored procedure which prevents commiting /rollbacking the transaction in the absence of exception handling. This causes the table locking and application
gets hang in next request
Below is the recommended approach...
set xact_abort on
Begin Try
Begin Tran
//SQl Query
Commit Tran
End Try
Begin Catch
Rollback Tran
End Catch
Related
I currently have an audit process that is part of all procedures and it is very basic at a high level.
Procedure is executed.
It inserts into the Audit table with a start time and status of Running.
It completes with out errors and then updates that record to show a status of Complete.
If there is an actual error it will update with a status of Error.
However if a user manually aborts the procedures via the SQL Server Management Studio no update will occur. The record will remain as "Running".
Is there any functionality I can use to capture this scenario so I can tie out the audit record?
You simply need to enclose it inside a transaction, and use XACT_ABORT for automatic rollback.
CREATE OR ALTER PROCEDURE YourProc
-- parameters here
AS
SET NOCOUNT, XACT_ABORT ON;
BEGIN TRAN;
-- everything else here
COMMIT;
Always use SET XACT_ABORT ON if you have a transaction. This ensures that if the code is aborted or it errors, the transaction will be rolled back and not left hanging.
Do not use TRY CATCH unless you want to actually handle the error and log it. It is not necessary to use CATCH to ensure a rollback if you have XACT_ABORT. If you do catch, then rethrow the error using THROW; rather than RAISERROR. For example:
BEGIN CATCH
IF XACT_STATE() <> 0
ROLLBACK;
INSERT Audit... ;
THROW;
END CATCH;
But note that certain errors cannot be caught, and a user abort cannot be caught either. I suggest you use XEvents for that .
I'm using an after update trigger on a table purely for testing purposes in order to force an error with an SSIS package. It's basically just a trigger that calls RAISERROR() with a static message after an update happens.
This works ok in most instances. However, when I call a specific stored procedure that contains a try/catch (no explicit transactions involved), and it updates the table, the update doesn't happen or is getting rolled back somehow. My understanding of Try/Catch was that it would not rollback unless you explicitly implemented BEGIN/COMMIT/ROLLBACK TRANSACTION.
I seem to be misunderstanding Try/Catch, or I'm misunderstanding how triggers function. I normally try not to use triggers, but for this use-case it made sense.
If I comment out the Try/Catch, everything functions as I'd expect.
CREATE PROCEDURE dbo.MySproc
AS
BEGIN
SET NOCOUNT ON;
BEGIN TRY
UPDATE dbo.MyTableToFireTrigger SET SomeColumn = 1 WHERE SomeColumn = 0
END TRY
BEGIN CATCH
--I'm able to log the after update trigger error message here, but it seems to be rolling back the update.
END CATCH;
END
Trigger create:
CREATE TRIGGER dbo.MyTrigger ON dbo.MyTableToCauseTrigger
AFTER UPDATE
AS
BEGIN
RAISERROR('Error', 16, 1);
END;
In a transaction if an error occurred that transaction will be rolled back. This refers to the transaction concept. When you call your stored procedure a transaction is started. Then it causes your trigger to be fired and the error raised. Automatically the transaction will be rolled back.
I am having a bit of hard time understanding how errors affect the completion of batches and/or transactions.
For instance:
BEGIN TRAN;
SELECT 1/0 AS Error;
ROLLBACK;
BEGIN TRAN;
SELECT 1/1 AS NOError;
COMMIT;
GO
Should not the second transaction succeed even though the first fails? Are not transactions dealt with on one-by-one basis? And what is the role played by batches here?
I was reading about SET XACT_ABORT ON command, and the MSDN says:
When SET XACT_ABORT is ON, if a Transact-SQL statement raises a run-time error, the entire transaction is terminated and rolled back.
If it only fails the containing transaction, why the second transaction is never reached?
USE AdventureWorks;
GO
BEGIN TRANSACTION;
GO
DELETE FROM HumanResources.JobCandidate WHERE JobCandidateID = 10;
DELETE FROM HumanResources.JobCandidate WHERE JobCandidateID = 11;
DELETE FROM HumanResources.JobCandidate WHERE JobCandidateID = 12;
GO
COMMIT TRANSACTION;
GO
What happens if the first delete statement fails? Will the 2nd and 3rd delete statements be executed? The example doesn't have any error handling, will it leave an open transaction in the case of an exception, or will SQL Server rollback the transaction automatically? Open transaction = locked resources, right?
I am deciding whether I must apply TRY...CATCH to stored procedures that use transactions.
I am aware about set xact_abort on, but want to know what happens without it.
Here is what I found in docs - Controlling Transactions (Database Engine):
If an error prevents the successful completion of a transaction, SQL Server automatically rolls back the transaction and frees all resources held by the transaction
However I read in other posts that automatic rollback is not fired.
In your example, without the use of SET XACT_ABORT ON, the transaction will continue and commit even if the first statement fails. In the text you quoted, the key words are if an error **prevents** the successful completion of a transaction, and a DELETE statement failing does not prevent the transaction from completing.
An example of an error that would cause an automatic rollback is if the connection to the database was severed in the middle of a transaction. Further down the MSDN article you referenced says:
If a run-time statement error (such as a constraint violation) occurs
in a batch, the default behavior in the Database Engine is to roll
back only the statement that generated the error. You can change this
behavior using the SET XACT_ABORT statement. After SET XACT_ABORT ON
is executed, any run-time statement error causes an automatic rollback
of the current transaction. Compile errors, such as syntax errors, are
not affected by SET XACT_ABORT.
It's always a good idea to use error handling to catch errors and rollback if needed.
I prefer to control the process manually:
BEGIN TRY
BEGIN TRAN
-- do work
COMMIT
END TRY
BEGIN CATCH
ROLLBACK
RAISERROR (...)
END CATCH
GO
I have a stored procedure which is called inside a trigger on Insert/Update/Delete.
The problem is that there is a certain code block inside this SP which is not critical.
Hence I want to ignore any erros arising from this code block.
I inserted this code block inside a TRY CATCH block. But to my surprise I got the following error:
The current transaction cannot be committed and cannot support operations that write to the log file. Roll back the transaction.
Then I tried using SAVE & ROLLBACK TRANSACTION along with TRY CATCH, that too failed with the following error:
The current transaction cannot be committed and cannot be rolled back to a savepoint. Roll back the entire transaction.
My server version is: Microsoft SQL Server 2008 (SP2) - 10.0.4279.0 (X64)
Sample DDL:
IF OBJECT_ID('TestTrigger') IS NOT NULL
DROP TRIGGER TestTrigger
GO
IF OBJECT_ID('TestProcedure') IS NOT NULL
DROP PROCEDURE TestProcedure
GO
IF OBJECT_ID('TestTable') IS NOT NULL
DROP TABLE TestTable
GO
CREATE TABLE TestTable (Data VARCHAR(20))
GO
CREATE PROC TestProcedure
AS
BEGIN
SAVE TRANSACTION Fallback
BEGIN TRY
DECLARE #a INT = 1/0
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION Fallback
END CATCH
END
GO
CREATE TRIGGER TestTrigger
ON TestTable
FOR INSERT, UPDATE, DELETE
AS
BEGIN
EXEC TestProcedure
END
GO
Code to replicate the error:
BEGIN TRANSACTION
INSERT INTO TestTable VALUES('data')
IF ##ERROR > 0
ROLLBACK TRANSACTION
ELSE
COMMIT TRANSACTION
GO
I was going through the same torment, and I just solved it!!!
Just add this single line at the very first step of your TRIGGER and you're going to be fine:
SET XACT_ABORT OFF;
In my case, I'm handling the error feeding a specific table with the batch that caused the error and the error variables from SQL.
Default value for XACT_ABORT is ON, so the entire transaction won't be commited even if you're handling the error inside a TRY CATCH block (just as I'm doing). Setting its value for OFF will cause the transaction to be commited even when an error occurs.
However, I didn't test it when the error is not handled...
For more info:
SET XACT_ABORT (Transact-SQL) | Microsoft Docs
I'd suggest re-architecting this so that you don't poison the original transaction - maybe have the transaction send a service broker message (or just insert relevant data into some form of queue table), so that the "non-critical" part can take place in a completely independent transaction.
E.g. your trigger becomes:
CREATE TRIGGER TestTrigger
ON TestTable
FOR INSERT, UPDATE, DELETE
AS
BEGIN
INSERT INTO QueueTable (Col1,Col2)
SELECT COALESCE(i.Col1,d.Col1),COALESCE(i.Col2,d.Col2) from inserted i,deleted d
END
GO
You shouldn't do anything inside a trigger that might fail, unless you do want to force the transaction that initiated the trigger action to also fail.
This is a very similar question to Why try catch does not suppress exception in trigger
Also see the answer here T-SQL try catch transaction in trigger
I don’t think you can use savepoints inside a trigger. I mean, you can but I googled about it and I saw a few people saying that they don’t work. If you replace your “save transaction” for a begin transaction, it compiles. Of course it is not necessary because you have the outer transaction control and the inner rollback would rollback everything.