SELECT FOR UPDATE with SQL Server

后端 未结 18 2226
自闭症患者
自闭症患者 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:14

    Create a fake update to enforce the rowlock.

    UPDATE <tablename> (ROWLOCK) SET <somecolumn> = <somecolumn> WHERE id=1
    

    If that's not locking your row, god knows what will.

    After this "UPDATE" you can do your SELECT (ROWLOCK) and subsequent updates.

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

    You have to deal with the exception at commit time and repeat the transaction.

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

    Revisit all your queries, maybe you have some query that select without ROWLOCK/FOR UPDATE hint from the same table you have SELECT FOR UPDATE.


    MSSQL often escalates those row locks to page-level locks (even table-level locks, if you don't have index on field you are querying), see this explanation. Since you ask for FOR UPDATE, i could assume that you need transacion-level(e.g. financial, inventory, etc) robustness. So the advice on that site is not applicable to your problem. It's just an insight why MSSQL escalates locks.


    If you are already using MSSQL 2005(and up), they are MVCC-based, i think you should have no problem with row-level lock using ROWLOCK/UPDLOCK hint. But if you are already using MSSQL 2005 and up, try to check some of your queries which query the same table you want to FOR UPDATE if they escalate locks by checking the fields on their WHERE clause if they have index.


    P.S.
    I'm using PostgreSQL, it also uses MVCC have FOR UPDATE, i don't encounter same problem. Lock escalations is what MVCC solves, so i would be surprised if MSSQL 2005 still escalate locks on table with WHERE clauses that doesn't have index on its fields. If that(lock escalation) is still the case for MSSQL 2005, try to check the fields on WHERE clauses if they have index.

    Disclaimer: my last use of MSSQL is version 2000 only.

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

    I have a similar problem, I want to lock only 1 row. As far as I know, with UPDLOCK option, SQLSERVER locks all the rows that it needs to read in order to get the row. So, if you don't define a index to direct access to the row, all the preceded rows will be locked. In your example:

    Asume that you have a table named TBL with an id field. You want to lock the row with id=10. You need to define a index for the field id (or any other fields that are involved in you select):

    CREATE INDEX TBLINDEX ON TBL ( id )
    

    And then, your query to lock ONLY the rows that you read is:

    SELECT * FROM TBL WITH (UPDLOCK, INDEX(TBLINDEX)) WHERE id=10.
    

    If you don't use the INDEX(TBLINDEX) option, SQLSERVER needs to read all rows from the beginning of the table to find your row with id=10, so those rows will be locked.

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

    Question - is this case proven to be the result of lock escalation (i.e. if you trace with profiler for lock escalation events, is that definitely what is happening to cause the blocking)? If so, there is a full explanation and a (rather extreme) workaround by enabling a trace flag at the instance level to prevent lock escalation. See http://support.microsoft.com/kb/323630 trace flag 1211

    But, that will likely have unintended side effects.

    If you are deliberately locking a row and keeping it locked for an extended period, then using the internal locking mechanism for transactions isn't the best method (in SQL Server at least). All the optimization in SQL Server is geared toward short transactions - get in, make an update, get out. That's the reason for lock escalation in the first place.

    So if the intent is to "check out" a row for a prolonged period, instead of transactional locking it's best to use a column with values and a plain ol' update statement to flag the rows as locked or not.

    0 讨论(0)
  • Try (updlock, rowlock)

    0 讨论(0)
提交回复
热议问题