當須要在多個Oracle數據庫之間進行數據一致性操做時,就會用到分佈式事務。
例如:html
insert into T_log@remote_db; --遠程數據庫插入 insert into T_local; --本地數據庫插入 commit;
分佈在本地和遠程兩個db的事務同時操做,這就構成了一個分佈式事務。git
分佈式事務採用Two-Phase Commit提交機制,保證分佈在各個節點的子事務可以所有提交或所有回滾的原子性。在這種機制下,事務處理過程分爲三個階段:github
- PREPARE:發起分佈式事務的節點通知各個關聯節點準備提交或回滾。各關聯節點此時會作三個事情:刷新redo信息到redo log中;將持有的鎖轉換爲懸疑事務鎖;取各節點中最大的SCN號進行同步
- COMMIT:寫入commited SCN,釋放鎖資源
- FORGET:懸疑事務表和關聯的數據庫視圖信息清理
因爲分佈式事務涉及到多個數據庫之間進行操做,偶爾會遇到一些異常狀況(例如系統或網絡中斷)致使上述三個階段出現異常,這就在一個或多個節點上,產生不完整的「懸疑分佈式事務」。
大多數狀況下,出現這種問題,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.
此時每每須要手工處理進行干預。網絡
如下是三種常見的分佈式事務問題場景:session
- dba_2pc視圖中有數據,但分佈式事務已經不存在
- 分佈式事務存在,但dba_2pc視圖中沒有數據
- 事務和視圖數據都有,可是執行commit force或rollback force時hang住
經過報錯會有提示,例如:oracle
ORA-01591: lock held by in-doubt distributed transaction 10.20.360 這個10.20.360就是咱們須要檢查分佈式事務ID
場景一:dba_2pc視圖中有數據,但分佈式事務已經不存在
視圖有數據,那麼先檢查數據的狀態分佈式
select * from dba_2pc_pending where local_tran_id='10.20.360';
主要看state字段。
若是事務已是committed, rollback forced或者commit forced狀態,表示事務已經完成了,可是在FORGET階段處理時,數據庫字典的信息沒能及時清除。此時,咱們調用oracle的清理丟失事務信息的語句就能夠完成處理:post
execute DBMS_TRANSACTION.PURGE_LOST_DB_ENTRY ('10.20.360');
若是事務是PREPARED狀態,可是在事務表中又沒有活動的事務:this
SELECT KTUXEUSN, KTUXESLT, KTUXESQN, /* Transaction ID */ KTUXESTA Status, KTUXECFL Flags FROM x$ktuxe WHERE ktuxesta!='INACTIVE' AND ktuxeusn= 10; --注意替換這裏的回滾段號(xid=usn.slot.(sqn+1)) ----沒有活動的事務
那此時須要手工清理丟失事務的信息
set transaction use rollback segment SYSTEM; delete from sys.pending_trans$ where local_tran_id = ; delete from sys.pending_sessions$ where local_tran_id = ; delete from sys.pending_sub_sessions$ where local_tran_id = ; commit;
場景二:分佈式事務存在,但dba_2pc視圖中沒有數據
遇到ORA-2054, ORA-1591等錯誤,檢查dba_2pc視圖沒有記錄,這種場景不常見,只在少數極端的狀況下出現。
先確認現象,分別檢查x$ktuxe和 dba_2pc_pending視圖,查詢語句與場景一相同
在這種狀況下不管是執行commit force仍是rollback force,都會直接拋出異常:
commit force '10.20.360'; ORA-02058: no prepared transaction found with ID 10.20.360
這時咱們須要將視圖對應的基表數據補入,而後再執行rollback force。
alter system disable distributed recovery; insert into pending_trans$ ( LOCAL_TRAN_ID, GLOBAL_TRAN_FMT, GLOBAL_ORACLE_ID,STATE, STATUS, SESSION_VECTOR,RECO_VECTOR,TYPE#, FAIL_TIME, RECO_TIME) values( '10.20.360', /* <== Replace this with your local tran id */ 306206, 'xxxxxxxx.00000.0.0.0', 'prepared','P', hextoraw( '00000001' ),hextoraw( '00000000' ), 0, sysdate, sysdate ); insert into pending_sessions$ values( '10.20.360',1, hextoraw('00000000'), 'C', 0, 1433927502, '', 14); --1433927502爲DBID, 14爲userid commit; rollback force '10.20.360'; EXECUTE DBMS_TRANSACTION.PURGE_LOST_DB_ENTRY('10.20.360'); --手工清理事務信息
場景三:事務和視圖數據都有,可是執行commit force或rollback force時hang住
若是視圖和事務表中都有數據,並且狀態是PREPARED,先執行commit force或rollback force,一般就能解決問題,但有時候也會遇到執行force處理時hang住
嘗試purge事務信息時,有提示報錯:
BEGIN DBMS_TRANSACTION.PURGE_LOST_DB_ENTRY('10.20.360'); END; * ERROR at line 1: ORA-06510: PL/SQL: unhandled user-defined exception ORA-06512: at "SYS.DBMS_TRANSACTION", line 94 ORA-06512: at line 1
此時須要進行場景一和場景二的結合起來的全部步驟:
1. 先將視圖對應的基表數據刪除 delete from sys.pending_trans$ where local_tran_id = '10.20.360'; delete from sys.pending_sessions$ where local_tran_id = '10.20.360'; delete from sys.pending_sub_sessions$ where local_tran_id ='10.20.360'; commit; 2. 再插入pending_trans$和pending_sessions$數據,見場景二 3. rollback force '10.20.360'; 4. Purge the transaction: exec dbms_transaction.purge_lost_db_entry('10.20.360');
完整實例:http://github.crmeb.net/u/defu
來自 「開源世界 」 ,連接:http://ym.baisou.ltd/post/645.html,如需轉載,請註明出處,不然將追究法律責任。