![](/img/trans.png)
[英]Workaround for Spring/Hibernate due to non-standard behaviour of UNIQUE constraint in MS SQL
[英]Spring Data/Hibernate MS SQL Server unique constraint and race condition
前段時間我遇到了競爭條件問題,當 2 個單獨的事務嘗試同時檢查記錄是否存在(按 4 個字段),如果不存在 - 創建一個新的。
我的環境:
MS SQL Server
, Spring Data
/ JPA
/ Hibernate
這是一個重復的記錄問題。 我實現了模擬並發調用的測試,因此能夠(在 99.99% 的執行時間下非常穩定)重現這個問題。
現在我通過對這 4 個字段應用唯一約束來解決這個問題。 目前我的測試無法重現這個問題。 我對它真的很滿意,但老實說,我並不完全了解它的工作原理。 這正是我創建這個問題的原因 - 我不明白為什么例如我的測試不會因ConstraintViolationException
而失敗,而兩個並發事務同時檢查記錄是否存在,然后嘗試創建它(每個)。 根據我的測試,我的理解是 - 兩個交易同時工作,在第一次檢查期間不應該找到任何記錄。 之后,他們應該嘗試創建新記錄,其中一個事務應該能夠完成,而另一個事務應該會因ConstraintViolationException
失敗。 但是代碼工作正常,一切正常,沒有任何異常。
Spring Data/JPA/Hibernate 級別甚至 MS SQL Server 是否有任何內部同步機制可以防止並發事務不正確工作並允許它們等待彼此的工作結果? 請解釋。 謝謝 !
這一切都取決於您在表上擁有的索引以及當時查詢所使用的索引。 如果不同的進程使用不同的執行計划來檢查行的不存在,那么由於 SQL Server 發出資源鎖的方式,它們都將返回 true 並添加一條記錄。
來自 [1]:
- 在執行寫操作時,SQL Server 不會鎖定相關的索引...,只鎖定相關的數據行。
- 執行讀取操作時,SQL Server 僅鎖定它在其訪問路徑中找到並使用的對象(例如索引、數據行等)。
通過在這 4 個字段上添加唯一約束,您隱式有效地添加了一個覆蓋索引,這導致您的所有進程使用相同的查詢計划,從而以相同的順序獲取相同對象的資源鎖。
有關資源鎖定的非常詳細的信息,請閱讀:[1] https://www.mssqltips.com/sqlservertip/1485/using-sql-server-indexes-to-bypass-locks/
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.