java mysql 死锁,java-Spring JPA MySQL和死锁
我正在研究使用Spring Boot在Java中實(shí)現(xiàn)的REST API.我使用了嵌入式內(nèi)存數(shù)據(jù)庫H2數(shù)周,但在某個(gè)時(shí)候我注意到事務(wù)隔離存在問題.
更準(zhǔn)確地說,我有一個(gè)表,需要在其中跟蹤“重復(fù)”記錄.重復(fù)只是一條記錄,對(duì)于表的列的定義明確的子集而言,它等于另一條記錄.因此,基本上,當(dāng)我插入新記錄時(shí),我首先檢查它是否重復(fù)并相應(yīng)地標(biāo)記它.布爾列“ duplicate”用于此目的.
例如,假設(shè)B和C是我為了定義重復(fù)項(xiàng)檢查的列.這是有效狀態(tài):
| A | B | C |重復(fù)|
| -| -| -| ——— |
| x | y | z |錯(cuò)誤
| z | y | z |真實(shí)|
| x | y | y |錯(cuò)誤
| x | y | y |真實(shí)|
| y | y | y |真實(shí)|
雖然這不是有效狀態(tài):
| A | B | C |重復(fù)|
| -| -| -| ——— |
| x | y | z |錯(cuò)誤
| z | y | z |真實(shí)|
| x | y | y |錯(cuò)誤
| x | y | y |真實(shí)|
| y | y | y |錯(cuò)誤
…因?yàn)榈?行和第5行的B和C值相同,因此必須將兩者之一標(biāo)記為重復(fù).
換句話說,我的要求是將碰巧已經(jīng)使用過的任何行標(biāo)記為重復(fù).給定一組值的僅一行將允許重復(fù)== false.
但是,基于Spring的實(shí)現(xiàn)無法按預(yù)期工作.例如,插入100個(gè)具有相同值的行應(yīng)導(dǎo)致99個(gè)重復(fù)項(xiàng),而只有一個(gè)非重復(fù)項(xiàng).但是,當(dāng)我嘗試并行執(zhí)行這些插入操作時(shí),沒有檢測(cè)到很多重復(fù)項(xiàng).
我嘗試了幾個(gè)修復(fù)程序,并且在某個(gè)時(shí)候我開始認(rèn)為H2沒有正確實(shí)現(xiàn)SERIALIZABLE隔離級(jí)別.我創(chuàng)建了一個(gè)小應(yīng)用程序來演示它:
@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);
}
}
注意:我省略了明顯的代碼,例如模型和存儲(chǔ)庫. Foo模型具有一個(gè)標(biāo)識(shí)符(UUID類型),一個(gè)bar屬性(String類型)和一個(gè)重復(fù)屬性(boolean類型).重復(fù)檢查基于bar屬性.
使用H2時(shí),我會(huì)錯(cuò)過很多重復(fù)項(xiàng)(通常為10%).使用MySQL我總是有正確的結(jié)果(即標(biāo)記為重復(fù)的行數(shù)正好是N-1,其中N是插入的行數(shù)).唯一的問題是只有一小部分插入成功(最多從1%到30%).
我遇到了大量與死鎖相關(guān)的異常.這是為什么?這樣簡單的代碼怎么會(huì)導(dǎo)致死鎖.我的意思是,這只是選擇,然后是插入.
有什么建議嗎?
解決方法:
應(yīng)用程序不應(yīng)在事務(wù)中檢查重復(fù)的密鑰本身.使用唯一索引將其留給數(shù)據(jù)庫引擎,如果發(fā)生異常,則捕獲異常,然后使用另一個(gè)標(biāo)識(shí)符重試.
如果您確實(shí)想在應(yīng)用程序級(jí)別解決此問題,則也許應(yīng)該在打開事務(wù)后立即手動(dòng)鎖定表.隔離級(jí)別可以自動(dòng)為您執(zhí)行此操作,但是會(huì)帶來較高的性能成本(您可能不希望這樣做).
另一個(gè)解決方案是使用@Version批注進(jìn)行樂觀鎖定,但是那樣您將不能保證標(biāo)識(shí)符的唯一性.
很難診斷死鎖問題,但是通常在您具有遞歸事務(wù)(在另一個(gè)事務(wù)中打開一個(gè)事務(wù))時(shí)出現(xiàn).檢查您的bean @Scope,它們可以創(chuàng)建此類問題.另外,請(qǐng)確保只有一個(gè)TransactionManager和一個(gè)EntityManager bean.
標(biāo)簽:jpa,deadlock,spring,java,mysql
來源: https://codeday.me/bug/20191111/2018614.html
總結(jié)
以上是生活随笔為你收集整理的java mysql 死锁,java-Spring JPA MySQL和死锁的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: php ajax sucess 失败,A
- 下一篇: 退回账单和退回额度有啥区别