SQL Server ROWLOCK over a SELECT if not exists INSERT transaction

12,113

An explanation...

  • ROWLOCK/PAGELOCK is granularity
  • XLOCK is mode

Granularity and isolation level and mode are orthogonal.

  • Granularity = what is locked = row, page, table (PAGLOCK, ROWLOCK, TABLOCK)

  • Isolation Level = lock duration, concurrency (HOLDLOCK, READCOMMITTED, REPEATABLEREAD, SERIALIZABLE)

  • Mode = sharing/exclusivity (UPDLOCK, XLOCK)

  • "combined" eg NOLOCK, TABLOCKX

XLOCK would have locked the row exclusively as you want. ROWLOCK/PAGELOCK wouldn't have.

Share:
12,113
IamIC
Author by

IamIC

An artistic engineer & humanitarian at heart. As a technology architect, I create solutions which take the confusions out of things. I love to help people.

Updated on June 05, 2022

Comments

  • IamIC
    IamIC almost 2 years

    I have upgraded from SQL Server 2005 to 2008. I remember that in 2005, ROWLOCK simply did not work and I had to use PAGELOCK or XLOCK to achieve any type of actual locking. I know a reader of this will ask "what did you do wrong?" Nothing. I conclusively proved that I could edit a "ROWLOCKED" row, but couldn't if I escalated the lock level. I haven't had a chance to see if this works in SQL 2008. My first question is has anyone come across this issue in 2008?

    My second question is as follows. I want to test if a value exists and if so, perform an update on relevant columns, rather than an insert of the whole row. This means that if the row is found it needs to be locked as a maintenance procedure could delete this row mid-process, causing an error.

    To illustrate the principle, will the following code work?

    BEGIN TRAN
    
    SELECT      ProfileID
    FROM        dbo.UseSessions
    WITH        (ROWLOCK)
    WHERE       (ProfileID = @ProfileID)
    OPTION      (OPTIMIZE FOR (@ProfileID UNKNOWN))
    
    if @@ROWCOUNT = 0 begin
        INSERT INTO dbo.UserSessions (ProfileID, SessionID)
        VALUES      (@ProfileID, @SessionID)
    end else begin
        UPDATE      dbo.UserSessions
        SET         SessionID = @SessionID, Created = GETDATE()
        WHERE       (ProfileID = @ProfileID)
    end
    
    COMMIT TRAN
    
  • IamIC
    IamIC over 13 years
    Thanks @gbn. So "WITH (XLOCK, ROWLOCK)" would do the trick :)
  • IamIC
    IamIC over 11 years
    oddly WITH (PAGELOCK) did lock the row. From what you're saying, I don't know why it would have.
  • Chris KL
    Chris KL about 9 years
    @IanC no it certainly wouldn't do the trick - read my answer above :)