客戶一套oracle11.2.0.4rac一體機,應用側抛來一個報錯
最開始看上去像是事務鎖,但是問客戶知道這是查的哪張表,客戶回報知道,就通過一般性事務去查了該表的鎖:
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';
我這個表有這個事務的資訊,而且狀态還是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;
很遺憾,我們查詢也是有活動的事務的
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
我這邊執行也确實報錯了
此時需要做如下操作:
删除對應分布式事務資訊,
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狀态了。
清理沒用的事務資訊
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');