你的事務到底提交成功沒有?
來自專欄資料庫內核技術專欄2 人贊了文章
無論你使用的是哪一種支持事務ACID的資料庫,比如Oracle server, MS SQL SERVER, MySQL, PostgreSQL 等等,當你執行完了一個事務,發出commit語句後,如果得到了返回結果,那麼這個結果可以告訴你這個事務是否提交成功。但是如果發出commit語句後,資料庫連接斷開了,或者阻塞得不到返回值,(最終可能因為各種超時而返回),你怎麼確定你的事務到底提交成功沒有?
這是用戶必須要解決的問題,但是也是一個對任何資料庫管理系統都沒有什麼完備和可靠的解決方案的問題。根據資料庫事務處理理論,一個資料庫系統需要確保如果它告知用戶一個事務提交成功,那麼該事務的改動必須持久保存。主流資料庫都可以保證這一點。但是在各種災難情況下無法告知用戶某個事務是否成功提交。用戶可以做的只能是查數據,比如上例的事務中你插入了一行,那麼斷連後你重連DB然後select那行看在不在。但是這麼做有兩個問題。
問題1:
你插入那行可能在這個時間窗口中已經被另一個事務修改或者刪除了,你找不到那行不代表那個事務提交就失敗了--- 它可能是成功了,也可能失敗了。總的來說這種情況下,沒有100%可靠的並且標準的方法,讓每種事務型資料庫提供給用戶去查,在這種斷連情況下,自己的事務到底提交成功沒有。
問題2:
你檢查之時那個提交還在進行中,所以你沒有查到。但是之後不久那個事務就提交成功了。這種情況下如果你依據這個檢查結果決定重複執行那個事務那麼可能出現嚴重的錯誤。想像一下轉賬的情形。並且這個問題完全無法完美解決。當資料庫系統負載很重時,處理commit的時耗比平時更長很多,此時也是客戶端發出commit得不到響應容易出現的時候。所以用戶用查數據的方法判斷是否提交成功的話,更容易得到錯誤的結果,認為一個事務沒有提交成功但是其實它提交成功了。這個問題基本無解。這兩個問題在單機資料庫系統和分散式資料庫系統中都存在。到目前為止這個問題仍然沒有一個標準的並且100%可靠的手段解決這個問題。下面我列出一些解決問題1 的備選方案以及它們的缺陷。
我們先討論一下單機的事務資料庫的情形。理論上我們可以使用事務redo日誌查找一個事務是否提交成功,但是redo日誌是定期清除的,在使用的系統中,redo日誌不可能一直增長,總是得清除的。那麼如果用戶的檢查是在清除之後那麼就無法得到正確的結果。如果我們把每個事務是否提交成功的結果記錄到另一個地方,比如一個表或者日誌文件,那麼那個實體也不得不定期清除。另外由於問題2的存在,這個redo日誌或者提交記錄被寫好之前用戶就做檢查的話,那麼會誤以為提交失敗了。也就是說,用戶只能在某個特定的但是起始時間不確定的時間段內可以得到準確的結果。
在TDSQL XA中,由於我們記錄了commit log,所以用戶可以在發出commit語句之後發生斷連或者客戶端程序crash等問題後,用select語句查找commit
log來確定一個事務是否將會提交成功。不過他只能在一定時間之後(比如斷連10秒之後)查,查到就代表一定會提交成功(但是此刻是否已經提交成功仍然是未知的),查不到就表示該事務的提交一定不會成功。不過由於commit
log也是會定期清除的,所以用戶在30分鐘後才查的話,就無法得到可靠的結果了。這裡還需要處理一些特殊情況,本文不再贅述,但是總的來說TDSQL XA的分散式事務處理機制在大量用戶實際使用驗證後證明是非常可靠的。
推薦閱讀:
※PostgreSQL串列化隔離級別(SSI)的能力與實現
※面試必備技能:JDK動態代理給Spring事務埋下的坑!
※Omid Transaction Processing