Tuesday, March 5, 2013

Locks in nested stored procedure

When a stored procedure(SP) calls nested stored procedure, if both the outer SP and inner SP have begin tran - commit tran statement, how long are the (exclusive) locks for the inner DML statement going to be held? That is, if the inner SP commits transaction, will the locks that acquired in the inner SP transaction be released? Or are their locks going to last all the way up to commit statement of outmost SP?
The short answer is it will last until the commit of the outmost SP.
Here is an simple experiment that can provide some proof.
CREATE PROC InnerSP
AS 
BEGIN        
 BEGIN TRAN        
    UPDATE dbo.Tab1
      SET Name='Name1'
      WHERE Id=1 
            
    SELECT 'After Update Tab1'            
    SELECT * FROM sys.dm_tran_locks
      WHERE resource_type != 'DATABASE'
    
    UPDATE dbo.Tab2
     SET City='Seattle'
     WHERE Id=1  
 COMMIT TRAN  
 
 SELECT '(InnerSP) After Commit'
 SELECT * FROM sys.dm_tran_locks 
   WHERE resource_type != 'DATABASE'
END
GO

CREATE PROC OuterSP
AS 
BEGIN        
  BEGIN TRAN  
     EXEC InnerSP
     -- cut --         
  COMMIT TRAN
  
  SELECT '(OuterSP) After Commit'    
  SELECT * FROM sys.dm_tran_locks    
    WHERE resource_type != 'DATABASE'
END
GO 

EXEC OuterSP

OuterSP calls InnerSP and InnerSP has BEGIN TRAN - COMMIT TRAN. If the exclusive locks are released after innerSP commit, dm_tran_locks will show no locks are held against Tab1 and Tab2 tables. But as shown below, the result is that the X locks are still intact after inner SP commit. Their locks are only released when outer SP commit is called.


The example above has UPDATE statements whose lock type is X (exclusive) lock. For Insert, Update, Delete, it holds X lock within a transaction, but for SELECT - within a transaction - the Shared (S) lock will be released once the rows are read in the default READ COMMITTED isolation level. If transaction isolation level is higher, S lock will last until it meets COMMIT.
On another note, if ROLLBACK is called in nested SP, the entire transaction is rolled back regardless of nested SP level. For example, when you have a SP that calls nestedSP1 that calls nestedSP2, if you call ROLLBACK in nestedSP2, the whole transaction from outmost SP will be rolled back. To avoid this, you can limit the transaction scope by using save transaction point. An example shown below rolls back nestedSP transaction only and UPDATE in outerSP is still valid.
CREATE PROC NestedSP
AS 
BEGIN        

BEGIN TRY            
  SAVE TRAN T2
    UPDATE dbo.Tab SET City='Redmond' WHERE Id=1  
    RAISERROR ('Error', 16, 1 );            
    COMMIT TRAN T2
END TRY                        
BEGIN CATCH            
    ROLLBACK TRAN T2
END CATCH            
            
END
GO

CREATE PROC OuterSP
AS 
BEGIN        
  BEGIN TRAN T1
 EXEC NestedSP
 -- cut --         
 UPDATE dbo.Tab SET City='Seattle' WHERE Id=1  
  COMMIT TRAN T1
END
GO 

EXEC OuterSP

No comments:

Post a Comment