SQLSERVER SELECT與INSERT死鎖及解決思路

場景中,問題可能就出在非聚集索引與聚集索引的死鎖問題上

步驟 Select過程 Insert過程
1 Select獲取到對應用戶抽獎記錄的行共享S鎖拿到rowId  
2   Insert獲取聚集索引的排它X鎖
3 根據rowId試圖獲取聚集索引的共享S鎖查詢其他列的數據,阻塞!  
4   Insert需要同步更新非聚集索引,試圖獲取排它鎖X,被S鎖阻塞!

所以死鎖發生了。。。

目前解決方案

  1. SQL語句添加 WITH (NOLOCK) 允許髒讀HQL語句Service的方法前添加
    @Transactional(isolation=ISOLATION.READ_UNCOMMITTED)
==============================================

The previous solution is not always preferable or applicable, for example, when the transaction that is blocking our queries is critical and not easy to be killed or rolled back, or when you don’t have control over other’s transactions within the database. In this case, the WITH (NOLOCK) table hint is useful here, if you can tolerate the risk of dirty reads or data inconsistency. As mentioned previously, the WITH (NOLOCK) table hint allows you to read the data that has been changed, but not committed to the database yet. If you run the same SELECT statement without killing, committing or rolling back the UPDATE transaction, but this time adding the WITH (NOLOCK) table hint to the table name in the SELECT statement as shown below:

 
1
SELECT * FROM LockTestDemo WITH ( NOLOCK )

Then checking the SELECT statement status using the sp_who2 command. You will see that the query is running without waiting for the UPDATE transaction to be completed successfully and release the locking on the table, as shown in the snapshot below:

The WITH (NOLOCK) table hint works the same as the READUNCOMMITTED table hint, allowing us to retrieve the data that is changed but not committed yet. The same SELECT statement can be modified to use the READUNCOMMITTED table hint as shown below:

1
SELECT * FROM LockTestDemo WITH ( READUNCOMMITTED )
如果INSERT寫入是強邏輯(理論上必須成功的),SELECT 按 READUNOCOMMITTED處理是安全的,但做好冪等處理。

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章