Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. Database & SysAdmin
  3. Database
  4. SQL record locking (to prevent other READS?)

SQL record locking (to prevent other READS?)

Scheduled Pinned Locked Moved Database
databasequestionsql-serversysadminbusiness
4 Posts 2 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • B Offline
    B Offline
    BungleBonce
    wrote on last edited by
    #1

    I have an application which selects one record at a time from a SQL SERVER 7.0 database. After doing some business logic, it's updates the same record with an status flag change. I need to run the application on 3 different machines concurrently. When I perform my SELECT of one row, how do I lock the selected record to prevent the same record being read by each instance of the application? Thanks in advance. :) Cheers Adrian

    A 1 Reply Last reply
    0
    • B BungleBonce

      I have an application which selects one record at a time from a SQL SERVER 7.0 database. After doing some business logic, it's updates the same record with an status flag change. I need to run the application on 3 different machines concurrently. When I perform my SELECT of one row, how do I lock the selected record to prevent the same record being read by each instance of the application? Thanks in advance. :) Cheers Adrian

      A Offline
      A Offline
      andyharman
      wrote on last edited by
      #2

      I normally do something like this:

      create procedure dbo.GetNextAvailable
      as begin
        declare @id int
        set nocount on
      
        --Start transaction so that locking works.
        begin tran
      
        --Get Id of next record to process.  The "holdlock" hint tells SQL
        --Server to place a lock on the row until the end of the transaction.
        --The "readpast" hint tells SQL-Server to ignore a record if it is
        --locked by one of your other two processes. Note that this only works
        --for "read committed" isolation.
        select top 1 @id = MyId from MyTable with (holdlock, readpast)
          where status = 'READY'
          order by MyId
      
        --Mark the record as "in-progress" so that no-one else can pick-up
        --the current record.
        update MyTable set status = 'IN PROGRESS'
          where MyId = @id
          and status = 'READY'
      
        --Complete the transaction.
        commit trans
      
        --Return the record to the front-end for processing.  If no records
        --returned then there are no records left to process.
        select * from MyTable where MyId = @id
      
        return(0)
      end
      

      You could potentially move the transaction outside of the stored procedure. I normally update the status to "SUCCESS" or "FAILURE" after I have completed processing of the record. If the record processing is substantial then I normally also maintain start and end times for each record. Regards Andy

      B 1 Reply Last reply
      0
      • A andyharman

        I normally do something like this:

        create procedure dbo.GetNextAvailable
        as begin
          declare @id int
          set nocount on
        
          --Start transaction so that locking works.
          begin tran
        
          --Get Id of next record to process.  The "holdlock" hint tells SQL
          --Server to place a lock on the row until the end of the transaction.
          --The "readpast" hint tells SQL-Server to ignore a record if it is
          --locked by one of your other two processes. Note that this only works
          --for "read committed" isolation.
          select top 1 @id = MyId from MyTable with (holdlock, readpast)
            where status = 'READY'
            order by MyId
        
          --Mark the record as "in-progress" so that no-one else can pick-up
          --the current record.
          update MyTable set status = 'IN PROGRESS'
            where MyId = @id
            and status = 'READY'
        
          --Complete the transaction.
          commit trans
        
          --Return the record to the front-end for processing.  If no records
          --returned then there are no records left to process.
          select * from MyTable where MyId = @id
        
          return(0)
        end
        

        You could potentially move the transaction outside of the stored procedure. I normally update the status to "SUCCESS" or "FAILURE" after I have completed processing of the record. If the record processing is substantial then I normally also maintain start and end times for each record. Regards Andy

        B Offline
        B Offline
        BungleBonce
        wrote on last edited by
        #3

        Thanks Andy, that looked like a good solution. However due to a Microsoft bug, I can't use the HOLDLOCK keyword with READPAST as I kept getting the following message: "You can only specify the READPAST lock in the READ COMMITTED or REPEATABLE READ isolation levels." The bug is confirmed in this KB article: http://support.microsoft.com/kb/171322[^]

        A 1 Reply Last reply
        0
        • B BungleBonce

          Thanks Andy, that looked like a good solution. However due to a Microsoft bug, I can't use the HOLDLOCK keyword with READPAST as I kept getting the following message: "You can only specify the READPAST lock in the READ COMMITTED or REPEATABLE READ isolation levels." The bug is confirmed in this KB article: http://support.microsoft.com/kb/171322[^]

          A Offline
          A Offline
          andyharman
          wrote on last edited by
          #4

          Your error message infers that your isolation level is not "committed read" (hence my warning about this in my original response). The MS article infers that you are trying to set the isolation-level in the "GetNext" SP, after the transaction has been started. If you are using ADO then the connection's "IsolationLevel" property should be set to "adXactReadCommitted" before the transaction starts. You need to be really careful about the isolation level and the scope of your transaction otherwise you will find that your separate processes will have to wait for each over to complete - if you do it really wrong then you could find that parallel processing actually takes longer than using just a single process. The technique that I specified should work even if you don't use the "READPAST" hist specified (so long as you don't start a transaction in your client-side code until AFTER you have called my SP. Hope that helps. Andy

          1 Reply Last reply
          0
          Reply
          • Reply as topic
          Log in to reply
          • Oldest to Newest
          • Newest to Oldest
          • Most Votes


          • Login

          • Don't have an account? Register

          • Login or register to search.
          • First post
            Last post
          0
          • Categories
          • Recent
          • Tags
          • Popular
          • World
          • Users
          • Groups