java mysql 死锁,java-Spring JPA MySQL和死锁
我正在研究使用Spring Boot在Java中實現的REST API.我使用了嵌入式內存數據庫H2數周,但在某個時候我注意到事務隔離存在問題.
更準確地說,我有一個表,需要在其中跟蹤“重復”記錄.重復只是一條記錄,對于表的列的定義明確的子集而言,它等于另一條記錄.因此,基本上,當我插入新記錄時,我首先檢查它是否重復并相應地標記它.布爾列“ duplicate”用于此目的.
例如,假設B和C是我為了定義重復項檢查的列.這是有效狀態:
| A | B | C |重復|
| -| -| -| ——— |
| x | y | z |錯誤
| z | y | z |真實|
| x | y | y |錯誤
| x | y | y |真實|
| y | y | y |真實|
雖然這不是有效狀態:
| A | B | C |重復|
| -| -| -| ——— |
| x | y | z |錯誤
| z | y | z |真實|
| x | y | y |錯誤
| x | y | y |真實|
| y | y | y |錯誤
…因為第3行和第5行的B和C值相同,因此必須將兩者之一標記為重復.
換句話說,我的要求是將碰巧已經使用過的任何行標記為重復.給定一組值的僅一行將允許重復== false.
但是,基于Spring的實現無法按預期工作.例如,插入100個具有相同值的行應導致99個重復項,而只有一個非重復項.但是,當我嘗試并行執行這些插入操作時,沒有檢測到很多重復項.
我嘗試了幾個修復程序,并且在某個時候我開始認為H2沒有正確實現SERIALIZABLE隔離級別.我創建了一個小應用程序來演示它:
@RestController
public class NewFooCtrl {
@Autowired
private FooRepo repo;
@RequestMapping(value = "/foo", method = RequestMethod.POST)
@Transactional(isolation = Isolation.SERIALIZABLE)
public void newFoo(@RequestBody Foo foo) {
List foos = repo.findByBar(foo.getBar());
if (foos.isEmpty()) foo.setDuplicate(false);
else foo.setDuplicate(true);
repo.save(foo);
}
}
注意:我省略了明顯的代碼,例如模型和存儲庫. Foo模型具有一個標識符(UUID類型),一個bar屬性(String類型)和一個重復屬性(boolean類型).重復檢查基于bar屬性.
使用H2時,我會錯過很多重復項(通常為10%).使用MySQL我總是有正確的結果(即標記為重復的行數正好是N-1,其中N是插入的行數).唯一的問題是只有一小部分插入成功(最多從1%到30%).
我遇到了大量與死鎖相關的異常.這是為什么?這樣簡單的代碼怎么會導致死鎖.我的意思是,這只是選擇,然后是插入.
有什么建議嗎?
解決方法:
應用程序不應在事務中檢查重復的密鑰本身.使用唯一索引將其留給數據庫引擎,如果發生異常,則捕獲異常,然后使用另一個標識符重試.
如果您確實想在應用程序級別解決此問題,則也許應該在打開事務后立即手動鎖定表.隔離級別可以自動為您執行此操作,但是會帶來較高的性能成本(您可能不希望這樣做).
另一個解決方案是使用@Version批注進行樂觀鎖定,但是那樣您將不能保證標識符的唯一性.
很難診斷死鎖問題,但是通常在您具有遞歸事務(在另一個事務中打開一個事務)時出現.檢查您的bean @Scope,它們可以創建此類問題.另外,請確保只有一個TransactionManager和一個EntityManager bean.
標簽:jpa,deadlock,spring,java,mysql
來源: https://codeday.me/bug/20191111/2018614.html
總結
以上是生活随笔為你收集整理的java mysql 死锁,java-Spring JPA MySQL和死锁的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: php ajax sucess 失败,A
- 下一篇: linux cmake编译源码,linu