Detecting dirty reads from a stored procedure

前端 未结 8 519
自闭症患者
自闭症患者 2021-02-04 02:27

I\'ve got 100 threads that are each calling the stored procedure as defined below.

How do I prevent dirty reads?

SET QUOTED_IDENTIFIER OFF
SET ANSI_NULLS         


        
8条回答
  •  生来不讨喜
    2021-02-04 02:58

    You need to replace this statement

    UPDATE CfgCerealNumber Set CerealNumber = CerealNumber + 1  
    WHERE CerealNumberID = @TableID
    

    by this:

    declare @CerealNumber int
    
    SELECT @CerealNumber = CerealNumber  + 1
    FROM CfgCerealNumber WITH (READCOMMITTED, READPAST, ROWLOCK) 
    WHERE CerealNumberID = @TableID
    
    if @CerealNumber is not null
        UPDATE CfgCerealNumber Set CerealNumber = @CerealNumber
        WHERE CerealNumberID = @TableID
    else
        raiserror ('Row was locked by another update (no dirty read and no deadlock happen) or no Table Record Exists in CfgCerealNumber for ID:%d   ', 
                  16,1, @TableID)
    

    these table hints READCOMMITTED, READPAST, ROWLOCK will make sure that you have no dirty read and no deadlock

    it will also let you decide if you still want to do an update

    READCOMMITTED
    Specifies that read operations comply with the rules for the READ COMMITTED isolation level by using either locking or row versioning. If the database option READ_COMMITTED_SNAPSHOT is OFF, the Database Engine acquires shared locks as data is read and releases those locks when the read operation is completed. If the database option READ_COMMITTED_SNAPSHOT is ON, the Database Engine does not acquire locks and uses row versioning.

    READPAST
    Specifies that the Database Engine not read rows that are locked by other transactions. When READPAST is specified, row-level locks are skipped. That is, the Database Engine skips past the rows instead of blocking the current transaction until the locks are released. For example, assume table T1 contains a single integer column with the values of 1, 2, 3, 4, 5. If transaction A changes the value of 3 to 8 but has not yet committed, a SELECT * FROM T1 (READPAST) yields values 1, 2, 4, 5. READPAST is primarily used to reduce locking contention when implementing a work queue that uses a SQL Server table. A queue reader that uses READPAST skips past queue entries locked by other transactions to the next available queue entry, without having to wait until the other transactions release their locks.

    ROWLOCK
    Specifies that row locks are taken when page or table locks are ordinarily taken. When specified in transactions operating at the SNAPSHOT isolation level, row locks are not taken unless ROWLOCK is combined with other table hints that require locks, such as UPDLOCK and HOLDLOCK.

    Source MSDN Table Hints (Transact-SQL)

    You might also need to use UPDLOCK and/or HOLDLOCK

提交回复
热议问题