天天看點

ORA-01591: lock held by in-doubt distributed transaction 20.25.280352

客戶一套oracle11.2.0.4rac一體機,應用側抛來一個報錯

ORA-01591: lock held by in-doubt distributed transaction 20.25.280352

最開始看上去像是事務鎖,但是問客戶知道這是查的哪張表,客戶回報知道,就通過一般性事務去查了該表的鎖:

SELECT lpad(' ',decode(l.xidusn ,0,3,0))||l.oracle_username User_name,

o.owner,o.object_name,o.object_type,s.sid,s.serial#

FROM v$locked_object l,dba_objects o,v$session s

WHERE l.object_id=o.object_id

AND l.session_id=s.sid 

AND upper(o.OBJECT_NAME) LIKE '%TO_ALERT_SMS_%'

ORDER BY o.object_id,xidusn DESC ;

發現該語句沒有任何傳回,意思到這可能不是一般的事務鎖。

搜尋該問題,發現有篇文章

在Oracle中,分布式事務ORA-01591錯誤如何解決? - 雲+社群 - 騰訊雲

裡面也是這種報錯,是一種分布式事務2節點送出鎖,大意就是,通過dblink連接配接另一個資料庫的表是,對另一個資料庫的表進行dml操作,同時也可能在同一個事務中對本庫中的本地表做事務送出操作,那麼對于dblink的表,需要確定遠端的資料庫也要送出,那麼在本地像遠端确認送出的時候,先由本地庫發一個prepare的确認資訊,遠端回複prepare了以後,本地在執行commit資訊;此種情況就是在本地執行commit以後,此時遠端庫還沒有完全commit,此時網絡中斷,導緻本地庫該表是commit狀态,但是遠端庫還是prepare狀态,一般來講,此時如果源端得到的事務資訊是全的,那麼資料庫不需要人為幹預,能夠自動根據事務資訊進行送出操作,但是出現這個問題的時候,基本就表示送出的事務資訊不足以讓遠端庫執行送出操作,是以此時這種事務就需要人為幹預了。

對于這樣的事務,在運氣好的情況下,對于這個事務,隻能通過連接配接網絡或者強制送出回退事務來結束。可以使用COMMIT FORCE或者ROLLBACK FORCE來進行處理,在這裡,進行復原操作,如下所示:

ROLLBACK FORCE '20.25.280352';
      

如果能執行過去,那麼該

而我這次情況下,執行這條語句會夯,客戶回報執行了8個小時,指令還未傳回。

恩墨寫了一篇文章,可以很好的解決這個問題

​​​​​​ORACLE懸疑分布式事務問題處理 - 墨天輪

1、查詢dba_2pc_pending表有資料,那麼要看資料的狀态

select * from dba_2pc_pending where local_tran_id='20.25.280352';

ORA-01591: lock held by in-doubt distributed transaction 20.25.280352

我這個表有這個事務的資訊,而且狀态還是prepared的狀态。

主要看state字段。

如果事務已經是committed, rollback forced或者commit forced狀态,表示事務已經完成了,但是在FORGET階段處理時,資料庫字典的資訊沒能及時清除。此時,我們調用oracle的清理丢失事務資訊的語句就可以完成處理:

execute DBMS_TRANSACTION.PURGE_LOST_DB_ENTRY ('20.25.280352');

 很遺憾,我們不是這種情況,我們是prepared的狀态,繼續下面的核查。

2、如果事務是PREPARED狀态,就需要在事務表中看是否有活動的事務,如果下面的查詢沒有傳回值,則說明活動表中沒有活動的事務,那麼可以直接執行下面的語句:

SELECT ktuxeusn,
ktuxeslt,
ktuxesqn,
ktuxesta status,
ktuxecfl flags
FROM x$ktuxe
WHERE ktuxesta != 'inactive'
AND ktuxeusn = 20
AND ktuxeslt = 25
AND ktuxesqn = 280352 ;
           

查詢條件就是傳回的事務鎖号"20.25.280352"拆開即可。如果沒有資料,則可以直接執行下面的操作手工清理丢失的事務資訊:

set transaction use rollback segment SYSTEM;
delete from sys.pending_trans$ where local_tran_id ='20.25.280352' ;
delete from sys.pending_sessions$ where local_tran_id = '20.25.280352';
delete from sys.pending_sub_sessions$ where local_tran_id = '20.25.280352';
commit;
           

很遺憾,我們查詢也是有活動的事務的

ORA-01591: lock held by in-doubt distributed transaction 20.25.280352

3、如果視圖和事務表中都有資料,而且狀态是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
           

 我這邊執行也确實報錯了

ORA-01591: lock held by in-doubt distributed transaction 20.25.280352

此時需要做如下操作:

删除對應分布式事務資訊,

delete from sys.pending_trans$ where local_tran_id = '20.25.280352';

delete from sys.pending_sessions$ where local_tran_id = '20.25.280352';

delete from sys.pending_sub_sessions$ where local_tran_id ='20.25.280352';

commit;
           

 禁用自動分布式恢複

alter system disable distributed recovery;
           

再次插入對應事務id的分布式資訊,下面兩條語句除了local_tran_id需要更改成你實際情況的事務id,其他資訊可以跟我一樣,原封不動的插入進去即可,因為該資訊本身就是随意提供的,隻是為了後面復原使用。 

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     ( '20.25.280352', /* <== Replace this with your local tran id */
             306206,
             '123.12345.1.2.3',
             'prepared',
             'p',
             Hextoraw('00000001'),
             Hextoraw('00000000'),
             0,
             sysdate,
             sysdate );

INSERT INTO pending_sessions$
VALUES     ( '20.25.280352',/* <==replace only this with your local tran id */
             1,
             Hextoraw('05004f003a1500000104'),
             'c',
             0,
             30258592,
             '',
             146 );
             
             
commit ;
           

復原事務

rollback force '20.25.280352';
           

重新啟用自動分布式事務恢複

alter system enable distributed recovery;
           

此時在pending表中檢視我們剛才插入的資訊,會發現state狀态字段會變成force rollback狀态了。

ORA-01591: lock held by in-doubt distributed transaction 20.25.280352

清理沒用的事務資訊

exec dbms_transaction.purge_lost_db_entry('20.25.280352');
           

 此步做完,下面的pending表就差不到復原的事務資訊了,此時表的分布式事務就解除了,表就能正常使用了。

select * from dba_2pc_pending where local_tran_id='20.25.280352';

後記:還有一種情況,我們本次未遇到,就是分布式事務存在,但dba_2pc(pending表)視圖中沒有資料

遇到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;
           

插入pending表事務資訊

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';
           

 重新啟用分布式事務自動恢複

alter system enable distributed recovery;
           

手工清理分布式事務陳舊資訊

EXECUTE DBMS_TRANSACTION.PURGE_LOST_DB_ENTRY('10.20.360');