在Oracle中,分散式事務ORA-01591錯誤如何解決?
- 2019 年 11 月 23 日
- 筆記
♣
題目部分
在Oracle中,分散式事務ORA-01591錯誤如何解決?
♣
答案部分
1、故障環境介紹
項目 |
資料庫 |
---|---|
DB類型 |
RAC |
DB版本 |
11.2.0.3 |
DB存儲 |
ASM |
OS版本及kernel版本 |
AIX 64位 6.1.0.0 |
2、故障發生現象及報錯資訊
有同事發來錯誤,截圖如下:

執行一個UPDATE語句的時候報ORA-01591的錯誤。

3、故障分析及解決過程
這個錯誤是由於分散式事務引起,而不是普通的鎖引起的。若檢查一般對象數據表鎖定,則只需要檢查V$LOCKED_OBJECT和V$TRANSACTION視圖,就可以定位到具體的SQL語句和操作人等資訊,但是檢查之後的結果如下:
1SYS@oraLHR12> SELECT * FROM GV$LOCKED_OBJECT; 2no rows selected 3SYS@oraLHR12> SELECT * FROM GV$TRANSACTION; 4no rows selected
兩個關鍵視圖中,沒有鎖定的對象,也沒有正在進行未提交的事務。那是不是沒有鎖定呢?或者鎖已經釋放了,重新嘗試對數據表加鎖,如下所示:
1SYS@oraLHR12> SELECT * FROM LHR.LHRBOKBAL FOR UPDATE; 2select * from LHR.LHRBOKBAL for update 3 * 4ERROR at line 1: 5ORA-01591: lock held by in-doubt distributed transaction 20.13.14721 6SYS@oraLHR12> SELECT COUNT(1) FROM LHR.LHRBOKBAL; 7 COUNT(1) 8---------- 9 30998411
系統沒有像一般阻塞那樣等待,而是報錯ORA-01591的錯誤,並且提示鎖被一個分散式事務持有,不能實現加鎖操作。那麼ORA-01591錯誤究竟是什麼錯誤呢?可以使用Oracle提供的oerr工具查看該錯誤編號,如下所示:
1root@ZFLHRRSP:/# oerr ora 1591 201591, 00000, "lock held by in-doubt distributed transaction %s" 3// *Cause: Trying to access resource that is locked by a dead two-phase commit 4// transaction that is in prepared state. 5// *Action: DBA should query the pending_trans$ and related tables, and attempt 6// to repair network connection(s) to coordinator and commit point. 7// If timely repair is not possible, DBA should contact DBA at commit 8// point if known or end user for correct outcome, or use heuristic 9// default if given to issue a heuristic commit or abort command to 10// finalize the local portion of the distributed transaction. 11
簡單的說,01591錯誤的原因是該對象被一個處在「IN-DOUBT」狀態的分散式事務鎖定。分散式事務使用的是「two-phase commit」二階段提交技術。解決該問題的方法就是查看內部表PENDING_TRANS$,確定分散式事務資訊。這種狀態的事務主要是由於在進行分散式事務時候,發生網路突發中斷的情況,引起分散式事務無法正常結束,等待中斷節點的事務響應。於是,各節點的事務所鎖定的表就不會被釋放掉。
此時,檢查視圖DBA_2PC_PENDING(或者基表PENDING_TRANS$),查看是否存在這種情況。

果然,當前存在一個阻塞分散式事務,處在prepared狀態。當前問題,主要是源於在進入prepared階段之後,發生了網路中斷的現象,引起COMMIT的階段不能等待到事務資訊。所以,才會一直處在Prepared狀態,數據表也就不會進行釋放。
對於這個事務,只能通過連接網路或者強制提交回退事務來結束。可以使用COMMIT FORCE或者ROLLBACK FORCE來進行處理,在這裡,進行回滾操作,如下所示:
1SYS@oraLHR12> ROLLBACK FORCE '20.13.14721'; 2Rollback complete.
ROLLBACK FORCE的參數是DBA_2PC_PENDING中記錄本地事務資訊的編號即LOCAL_TRAN_ID。
此時,再次查看數據。

此時,該事務狀態已經變化為forced rollback表示已經強制回退,此時再次嘗試鎖定表操作:
116:25:31 SQL> SELECT * FROM LHR.LHRBOKBAL FOR UPDATE; 2CURRENCY 3-------- 4001
可以看出已經不報錯了,可以正常執行。
& 說明:
有關該案例的更多內容可以參考我的BLOG:http://blog.itpub.net/26736162/viewspace-2122999/
本文選自《Oracle程式設計師面試筆試寶典》,作者:小麥苗