天天看點

日常Bug排查-應用Commit報錯事務并沒有復原

日常Bug排查-應用Commit報錯事務并沒有復原

前言

日常Bug排查系列都是一些簡單Bug排查,筆者将在這裡介紹一些排查Bug的簡單技巧,同時順便積累素材_。

應用Commit報錯并不一定復原

事實上,這篇文章并沒有什麼排查過程。但這個問題卻又是筆者經常遇到的。

筆者僅僅是想闡述一下當我們在事務Commit報錯時候,資料庫中的資料并不一定會是我們以為的復原狀态。筆者舉個例子:

日常Bug排查-應用Commit報錯事務并沒有復原

在這種情況下,很明顯的DB的資料肯定是處于已經送出的狀态。而如果App認為是復原狀态,并基于這個資訊去做操作的話,很明顯會導緻資料不一緻。

非IO or 逾時異常 也不一定復原

可能有人會問了,是不是僅僅是IO異常或者逾時異常才會出現這種不一定復原的問題呢?這裡還真不一定,筆者在一次Case中,就發現Oracle在commit的時候傳回死鎖異常時候,資料庫内部的commit竟然也成功了!這就牽涉到資料庫内部的處理了。

應用應該怎麼做呢?

事實上,由于資料庫保證了原子性。是以我們在遇到這種情況時候,需要從資料庫中重建狀态,而不是依賴現在應用裡面的資訊。是以遇到異常直接将流程結束,然後等定時任務等補單操作是個比較簡單安全的做法。

當然,資料庫中重建狀态時候,也要考慮到上一個相應的commit還在commit的過程中,隻不過這個commit非常慢而已。由于我們更新資料或者最終判斷的時候往往會鎖住資料,而資料庫一般都是采用了二階段鎖(S2PL)。

日常Bug排查-應用Commit報錯事務并沒有復原

在上一個commit成功送出之後,我們對相應資料的操作才會執行下去。是以隻要小心的控制好鎖的範圍,資料一緻性還是能保證的。

總結

Commit報錯但事務并沒有復原,這個雖然有點反直覺,但這确是在産線真實存在的,尤其在資料庫壓力大的時候極易出現。這個坑在我們編寫代碼的時候需要牢記!