在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程序员面试笔试宝典》,作者:小麦苗