數(shù)據(jù)庫中的ACID是事務(wù)的基本特性,而在Oracle等數(shù)據(jù)庫遷移到國產(chǎn)數(shù)據(jù)庫國產(chǎn)中,可能因為不同數(shù)據(jù)庫事務(wù)處理機制的不同,在遷移后的業(yè)務(wù)邏輯處理上存在差異。本文簡要介紹了事務(wù)的ACID屬性、事務(wù)的隔離級別、回滾機制和超時機制,并總結(jié)SAVEPOINT的使用,以總結(jié)。
1、數(shù)據(jù)庫中事務(wù)基本概念
事務(wù)是數(shù)據(jù)庫中的基本邏輯操作單元,由一組不可分割的數(shù)據(jù)庫操作序列組成,這些操作要么全部成功執(zhí)行,要么全部失敗回滾。其核心目的是確保數(shù)據(jù)的完整性和一致性,尤其在并發(fā)操作或系統(tǒng)故障時維護數(shù)據(jù)庫的可靠狀態(tài)。
1.1 事務(wù)基本屬性
ACID是事務(wù)的基本特性:原子性(Atomicity)、一致性(Consistency)、隔離性(Isolation)和持久性(Durability)。
原子性:事務(wù)中的所有操作必須作為一個整體執(zhí)行,要么全部執(zhí)行成功、要么全部失敗回滾,不允許出現(xiàn)部分成功的情況。在數(shù)據(jù)庫中通常是通過日志記錄(如undo log)來實現(xiàn)回滾操作,若事務(wù)執(zhí)行失敗,系統(tǒng)跟進日志撤銷已執(zhí)行的操作。
一致性:事務(wù)執(zhí)行前后,數(shù)據(jù)庫必須保持一致性狀態(tài)。所有數(shù)據(jù)必須滿足預(yù)定義的完整性約束(如主鍵、外鍵、唯一性約束等)。即使事務(wù)失敗,數(shù)據(jù)庫也不能破壞這些規(guī)則。在數(shù)據(jù)庫中通過一些約束和檢查來確保數(shù)據(jù)庫的完整性約束。
隔離性:多個事務(wù)并發(fā)執(zhí)行時,每個事務(wù)的操作應(yīng)與其他事務(wù)相互隔離,使得每個事務(wù)感覺不到其他事務(wù)的存在,最終效果應(yīng)與事務(wù)串行執(zhí)行的結(jié)果一致。數(shù)據(jù)庫中通過鎖機制(Locking)或多版本并發(fā)控制(MVCC)實現(xiàn),不同的隔離級別提供不同程度的隔離性。
持久性:事務(wù)一旦提交,其對數(shù)據(jù)庫的修改就是永久性的,即使系統(tǒng)發(fā)生故障(如斷電、崩潰),修改也不會丟失。數(shù)據(jù)庫中通過重做日志(Redo Log)實現(xiàn)持久性。提交事務(wù)時,對數(shù)據(jù)的修改首先寫入日志,再異步寫入數(shù)據(jù)庫文件中。當數(shù)據(jù)庫崩潰恢復(fù)時,通過重放日志恢復(fù)數(shù)據(jù)。
以轉(zhuǎn)賬交易為例,通過undo日志實現(xiàn)原子性,確保“扣款”和“存款”兩個操作要么全部成功,要么全部失敗;一致性是確保轉(zhuǎn)賬前后,數(shù)據(jù)庫必須滿足業(yè)務(wù)規(guī)則(如余額不為負、總額不變);通過鎖機制和MVCC多版本并發(fā)控制來實現(xiàn)事務(wù)的隔離性,多個并發(fā)轉(zhuǎn)賬操作互不干擾,結(jié)果與串行執(zhí)行一致;持久性則是一旦轉(zhuǎn)賬成功,即使系統(tǒng)崩潰,修改也不會丟失。
1.2 事務(wù)回滾機制
事務(wù)的原子性要求事務(wù)要么全部執(zhí)行成功、要么全部執(zhí)行失敗回滾,但是對于Oracle數(shù)據(jù)庫支持語句級的原子性,也就是一個事務(wù)中單個語句執(zhí)行失敗,則只會回滾該語句執(zhí)行的操作,不會導(dǎo)致在當前事務(wù)中丟失之前的任何工作。如果需要回滾整個事務(wù),需要處理錯誤并且主動調(diào)用ROLLBACK。這種語句級的回滾對于處理一些長時間運行的批處理任務(wù)有用,邏輯上希望能夠處理錯誤,不需要回滾已經(jīng)完成的所有操作。
1.3 事務(wù)超時機制
數(shù)據(jù)庫中事務(wù)會設(shè)置不同的超時機制,防止因為出現(xiàn)等鎖而出現(xiàn)無限等待,超過這個時間后會出現(xiàn)等鎖超時,事務(wù)會回滾。
Oracle數(shù)據(jù)庫:默認不會主動終止因行鎖等待而阻塞的事務(wù),事務(wù)會無限期等待鎖釋放,需由應(yīng)用層處理或手動終止,行鎖在事務(wù)提交或回滾是自動釋放;事務(wù)默認也無超時設(shè)置,但是可以限制會話的空閑時間,超過時間后會斷開鏈接。
MySQL數(shù)據(jù)庫:通過 innodb_lock_wait_timeout 控制,默認為50秒。當事務(wù)等待鎖超過此時間時,會拋出錯誤;事務(wù)中無默認超時時間,但是連接的空閑超時設(shè)置wait_timeout,默認8小時。
PostgreSQL:通過pg_lock_timeout設(shè)置行鎖等待超時時間,默認為0無限等待;事務(wù)中設(shè)置statement_timeout 控制單條SQL執(zhí)行時間,默認無限制。
TiDB:兼容MySQL行鎖等待設(shè)置;如果是悲觀事務(wù),默認TTL(Time-To-Live)為 1小時,超時后自動回滾,另外通過tidb_idle_transaction_timeout 控制空閑事務(wù)。
OceanBase:MySQL模式下兼容MySQL設(shè)置;事務(wù)中通過 ob_query_timeout 控制事務(wù)單條語句執(zhí)行時間,默認1800s
GoldenDB:兼容MySQL設(shè)置
GaussDB:參數(shù)lockwait_timeout控制單個鎖的最長等待時間,當申請的鎖等待時間超過設(shè)定值時,系統(tǒng)會報錯,默認為20min;通過通過 statement_timeout 控制單個語句執(zhí)行時長,默認0表示不控制。