目錄
我們在使用 oracle 資料庫時,有時候會碰到需要使用分布式事務,并且會碰到一些報錯!
當需要在多個Oracle資料庫之間進行資料一緻性操作時,就會用到分布式事務。
例如:
insert into T_log@remote_db; --遠端資料庫插入
insert into T_local; --本地資料庫插入
commit;
分布在本地和遠端兩個db的事務同時操作,這就構成了一個分布式事務。
分布式事務采用
Two-Phase Commit
送出機制,保證分布在各個節點的子事務能夠全部送出或全部復原的原子性。
在這種機制下,事務處理過程分為三個階段:
- PREPARE:發起分布式事務的節點通知各個關聯節點準備送出或復原。
- COMMIT:寫入commited SCN,釋放鎖資源
- FORGET:懸疑事務表和關聯的資料庫視圖資訊清理
各關聯節點此時會做三個事情:重新整理redo資訊到redo log中;将持有的鎖轉換為懸疑事務鎖;取各節點中最大的SCN号進行同步!
以下是三種常見的分布式事務問題場景:
- dba_2pc視圖中有資料,但分布式事務已經不存在
- 分布式事務存在,但dba_2pc視圖中沒有資料
- 事務和視圖資料都有,但是執行commit force或rollback force時hang住
通過報錯會有提示,例如:
ORA-01591: lock held by in-doubt distributed transaction 10.20.360
這個10.20.360就是我們需要檢查分布式事務ID!
由于分布式事務涉及到多個資料庫之間進行操作,偶爾會遇到一些異常情況(例如系統或網絡中斷)導緻上述三個階段出現異常,這就在一個或多個節點上,産生不完整的“懸疑分布式事務”。
大多數情況下,出現這種問題,Oracle 會由 Reco 程序進行自動修複,Oracle 資料庫會在
dba_2pc_pending
和
dba_2pc_neighbors
等多個視圖中記錄分布式事務相關的資訊,事實上 reco 程序也是基于這些資訊去做自動修複的。
Reco
程序會嘗試連接配接到其他節點擷取分布式事務資訊,然後嘗試修複失敗的事務,并将對應的事務中的記錄删除。
但有些情況下(例如節點無法正常通路或事務表中記錄的資料不完整),Reco 程序不能正常完成這個工作,就會抛出異常。
對于分布式事務,對應的異常代碼區間是
ORA-02040 - ORA-02099
,可通過alert日志檢視到錯誤資訊。
ORA-02054: transaction in-doubt
The transaction is neither committed or rolled back locally, and we have lost communication with the global coordinator.
此時往往需要手工處理進行幹預。
常用的 2pc_clean 指令如下:
select 'rollback force '||''''||local_tran_id||''''||';' "RollBack"
from dba_2pc_pending
where state='prepared';
select 'exec dbms_transaction.purge_lost_db_entry('||''''||local_tran_id||''''||');' "Purge"
from dba_2pc_pending;
select 'rollback force ''' || LOCAL_TRAN_ID || ''';' || chr(10) ||
'execute DBMS_TRANSACTION.PURGE_LOST_DB_ENTRY(''' || LOCAL_TRAN_ID
|| ''');' || chr(10) || 'commit;' from DBA_2PC_PENDING;