日常Bug排查-應(yīng)用Commit報錯事務(wù)并沒有回滾
日常Bug排查系列都是一些簡單Bug排查,筆者將在這里介紹一些排查Bug的簡單技巧,同時順便積累素材_。
應(yīng)用Commit報錯并不一定回滾
事實上,這篇文章并沒有什么排查過程。但這個問題卻又是筆者經(jīng)常遇到的。
筆者僅僅是想闡述一下當我們在事務(wù)Commit報錯時候,數(shù)據(jù)庫中的數(shù)據(jù)并不一定會是我們以為的回滾狀態(tài)。筆者舉個例子:
在這種情況下,很明顯的DB的數(shù)據(jù)肯定是處于已經(jīng)提交的狀態(tài)。而如果App認為是回滾狀態(tài),并基于這個信息去做操作的話,很明顯會導(dǎo)致數(shù)據(jù)不一致。
非IO or 超時異常 也不一定回滾
可能有人會問了,是不是僅僅是IO異常或者超時異常才會出現(xiàn)這種不一定回滾的問題呢?這里還真不一定,筆者在一次Case中,就發(fā)現(xiàn)Oracle在commit的時候返回死鎖異常時候,數(shù)據(jù)庫內(nèi)部的commit竟然也成功了!這就牽涉到數(shù)據(jù)庫內(nèi)部的處理了。
應(yīng)用應(yīng)該怎么做呢?
事實上,由于數(shù)據(jù)庫保證了原子性。所以我們在遇到這種情況時候,需要從數(shù)據(jù)庫中重建狀態(tài),而不是依賴現(xiàn)在應(yīng)用里面的信息。所以遇到異常直接將流程結(jié)束,然后等定時任務(wù)等補單操作是個比較簡單安全的做法。
當然,數(shù)據(jù)庫中重建狀態(tài)時候,也要考慮到上一個相應(yīng)的commit還在commit的過程中,只不過這個commit非常慢而已。由于我們更新數(shù)據(jù)或者最終判斷的時候往往會鎖住數(shù)據(jù),而數(shù)據(jù)庫一般都是采用了二階段鎖(S2PL)。
在上一個commit成功提交之后,我們對相應(yīng)數(shù)據(jù)的操作才會執(zhí)行下去。所以只要小心的控制好鎖的范圍,數(shù)據(jù)一致性還是能保證的。
總結(jié)
Commit報錯但事務(wù)并沒有回滾,這個雖然有點反直覺,但這確是在產(chǎn)線真實存在的,尤其在數(shù)據(jù)庫壓力大的時候極易出現(xiàn)。這個坑在我們編寫代碼的時候需要牢記!
本文轉(zhuǎn)載自微信公眾號「解Bug之路」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請聯(lián)系解Bug之路公眾號。