SELECT FOR UPDATE with SQL Server

后端 未结 18 2227
自闭症患者
自闭症患者 2020-11-27 11:49

I\'m using a Microsoft SQL Server 2005 database with isolation level READ_COMMITTED and READ_COMMITTED_SNAPSHOT=ON.

Now I want to use:

相关标签:
18条回答
  • 2020-11-27 12:33

    How about trying to do a simple update on this row first (without really changing any data)? After that you can proceed with the row like in was selected for update.

    UPDATE dbo.Customer SET FieldForLock = FieldForLock WHERE CustomerID = @CustomerID
    /* do whatever you want */
    

    Edit: you should wrap it in a transaction of course

    Edit 2: another solution is to use SERIALIZABLE isolation level

    0 讨论(0)
  • 2020-11-27 12:34

    Recently I had a deadlock problem because Sql Server locks more then necessary (page). You can't really do anything against it. Now we are catching deadlock exceptions... and I wish I had Oracle instead.

    Edit: We are using snapshot isolation meanwhile, which solves many, but not all of the problems. Unfortunately, to be able to use snapshot isolation it must be allowed by the database server, which may cause unnecessary problems at customers site. Now we are not only catching deadlock exceptions (which still can occur, of course) but also snapshot concurrency problems to repeat transactions from background processes (which cannot be repeated by the user). But this still performs much better than before.

    0 讨论(0)
  • 2020-11-27 12:37

    According to this article, the solution is to use the WITH(REPEATABLEREAD) hint.

    0 讨论(0)
  • 2020-11-27 12:39

    I'm assuming you don't want any other session to be able to read the row while this specific query is running...

    Wrapping your SELECT in a transaction while using WITH (XLOCK,READPAST) locking hint will get the results you want. Just make sure those other concurrent reads are NOT using WITH (NOLOCK). READPAST allows other sessions to perform the same SELECT but on other rows.

    BEGIN TRAN
      SELECT *
      FROM <tablename> WITH (XLOCK,READPAST) 
      WHERE RowId = @SomeId
    
      -- Do SOMETHING
    
      UPDATE <tablename>
      SET <column>=@somevalue
      WHERE RowId=@SomeId
    COMMIT
    
    0 讨论(0)
  • 2020-11-27 12:40

    You cannot have snapshot isolation and blocking reads at the same time. The purpose of snapshot isolation is to prevent blocking reads.

    0 讨论(0)
  • 2020-11-27 12:41

    perhaps making mvcc permanent could solve it (as opposed to specific batch only: SET TRANSACTION ISOLATION LEVEL SNAPSHOT):

    ALTER DATABASE yourDbNameHere SET READ_COMMITTED_SNAPSHOT ON;
    

    [EDIT: October 14]

    After reading this: Better concurrency in Oracle than SQL Server? and this: http://msdn.microsoft.com/en-us/library/ms175095.aspx

    When the READ_COMMITTED_SNAPSHOT database option is set ON, the mechanisms used to support the option are activated immediately. When setting the READ_COMMITTED_SNAPSHOT option, only the connection executing the ALTER DATABASE command is allowed in the database. There must be no other open connection in the database until ALTER DATABASE is complete. The database does not have to be in single-user mode.

    i've come to conclusion that you need to set two flags in order to activate mssql's MVCC permanently on a given database:

    ALTER DATABASE yourDbNameHere SET ALLOW_SNAPSHOT_ISOLATION ON;
    ALTER DATABASE yourDbNameHere SET READ_COMMITTED_SNAPSHOT ON;
    
    0 讨论(0)
提交回复
热议问题