转载ORA-01591错误故障处理(ji)

来源:这里教程网 时间:2026-03-03 16:47:51 作者:

ORA-01591 错误故障处理

摘要

在访问某些表的特定行时报ORA-01591错误

select * from BF_INCOME_EXPENSES_T

where account_id = 36816153

and user_id = 39964213

and city_code = '185'

ORA-01591:  锁定已被有问题的分配事务处理 72.0.1608712 挂起

SQL> select count(*) from UNITELE.BI_MQSYNC_SOURCE_CONTROL_T1;

ORA-01591:  锁定已被有问题的分配事务处理 72.0.1608712 挂起

由于该表是业务关键表,部分前台业务受到影响。

关键词: ORA-01591 DBA_2PC_PENDING  分布式事务

1. 故障分析

首先,在遇到ORA错误时,我们不可能知道每个ORA错误都是什么意思,所以通过oracle的联机文档查错误的cause和action可以让我们初步了解该错误。

01591, 00000, "lock held by in-doubt distributed transaction %s"

// *Cause: Trying to access resource that is locked by a dead two-phase commit

// transaction that is in prepared state.

// *Action: DBA should query the pending_trans$ and related tables, and attempt

// to repair network connection(s) to coordinator and commit point.

// If timely repair is not possible, DBA should contact DBA at commit

// point if known or end user for correct outcome, or use heuristic

// default if given to issue a heuristic commit or abort command to

// finalize the local portion of the distributed transaction.

Oracle 对ORA-01591错误的描述是"lock held by in-doubt distributed transaction %s,由分布式事务持有锁造成的。通过错误的cause可以看到’Trying to access resource that is locked by a dead two-phase commit transaction that is in prepared state’该错误是由访问一个处于prepared状态的二阶段事务所持有锁的资源造成的。

下面简单介绍一下分布式事务。

分布式事务,简单来说,是指一个事务在本地和远程执行,本地需要等待确认远程的事务结束后,进行下一步本地的操作。如通过dblink update远程数据库的一行记录,如果在执行过程中网络异常,或者其他事件导致本地数据库无法得知远程数据库的执行情况,此时就会发生in doublt的报错。此时需要dba介入,且需要分多种情况进行处理。

分布式事务的,会经历3个阶段:

1.PREPARE PHASE

1.1  决定哪个数据库为commit point site。(注,参数文件中commit_point_strength值高的那个数据库为commit point site)

1.2  全局协调者(Global Coordinator)要求所有的点(除commit point site外)做好commit或者rollback的准备。此时,对分布式事务的表加锁。

1.3  所有分布式事务的节点将它的scn告知全局协调者。

1.4  全局协调者取各个点的最大的scn作为分布式事务的scn。

至此,所有的点都完成了准备工作,我们开始进入COMMIT PHASE阶段,此时除commit point site点外所有点的事务均为in doubt状态,直到COMMIT PHASE阶段结束。

2.COMMIT PHASE : 2.1 Global Coordinator将最大scn传到commit point site,要求其commit。 2.2 commit point尝试commit或者rollback。分布式事务锁释放。 2.3 commit point通知Global Coordinator已经commit。 2.4 Global Coordinator通知分布式事务的所有点进行commit。

3.FORGET PHASE : 3.1 参与的点通知commit point site他们已经完成commit,commit point site就能忘记(forget)这个事务。 3.2 commit point site在远程数据库上清除分布式事务信息。 3.3 commit point site通知Global Coordinator可以清除本地的分布式事务信息。 3.4 Global Coordinator清除分布式事务信息。

有关分布式事务的详细信息请参阅oracle联机文档.

当前的分布式事务处于 Two-Phase Commit 机制中的prepared阶段,这个阶段事务已经在表上加锁了, 现在我们要访问这些表,但事务没有结束,一直持有锁,导致访问资源失败报ORA-01591。(在这里需要指出:分布式事务所持有的锁之所以堵塞读操作,是因为oralce不知道该显示哪个版本的数据) 如果结束这个事务,那相应的锁也会释放,这样就能解决这个问题。我们知道要结束一个事务有两种办法:commit和rollback。现在我们尝试结束这个事务:

commit force '72.0.1608712';

ORA-02058: no prepared transaction found with ID 72.0.1608712

报错并没有发现prepared状态的事务,由于该事务是分布式事务,我们首先想到的是dba_2pc_pending这个试图

SQL> select * from dba_2pc_pending;

no rows selected

该试图并没有查到信息,所以我们无法用commit force结束这个分布式事务,那么现在我们查看是否存在该事务, 通过实际报错,我们可以清晰的看到事务号为72.0.1608712,该事务在72号回滚段的0号事务槽上并且序列号是1608712, 这时查询一个基表x$ktuxe,看看72号回滚段上是否有该事务。

SQL> SELECT KTUXEUSN, KTUXESLT, KTUXESQN, /* Transaction ID */

2 KTUXESTA Status,

3 KTUXECFL Flags

4 FROM x$ktuxe

5 WHERE ktuxesta!='INACTIVE'

6 AND ktuxeusn= 72;

KTUXEUSN KTUXESLT KTUXESQN STATUS FLAGS

---------- ---------- ---------- ---------------- ------------------------

72 0 1608712 PREPARED SCO|COL|REV|DEAD

通过x$ktuxe这个基表,我们看到确实存在这个事务,而且是prepared状态。

此时,我们基本清楚了这个问题的原因:当一个分布式事务死掉时,由于该事务没有正常结束,导致事务持有的锁一直没有释放,所以在访问这个事务涉及的资源时,申请不到锁资源,所以报ORA-01591。由于是分布式事务,当在dba_2pc_pending中查询不到事务信息时,我们是无法通过commit或者rollback结束该事务。

所以,我们目前的任务是模拟出这个分布式事务。由于dba_2pc_pending试图是依赖于pending_trans$这个表,同时事务是与session关联在一起的,所以我们需要手工往pending_trans$和pending_sessions$两个表中插入数据。

2. 故障处理

SQL> alter system disable distributed recovery;

系统已更改。

SQL> insert into pending_trans$ (

2 LOCAL_TRAN_ID,

3 GLOBAL_TRAN_FMT,

4 GLOBAL_ORACLE_ID,

5 STATE,

6 STATUS,

7 SESSION_VECTOR,

8 RECO_VECTOR,

9 TYPE#,

10 FAIL_TIME,

11 RECO_TIME)

12 values( '72.0.1608712',

13 306206,

14 'XXXXXXX.12345.1.2.3',

15 'prepared','P',

16 hextoraw( '00000001' ),

17 hextoraw( '00000000' ),

18 0, sysdate, sysdate );

已创建 1 行。

SQL> insert into pending_sessions$

2 values( '72.0.1608712',

3 1, hextoraw('05004F003A1500000104'),

4 'C', 0, 30258592, '',

5 146

6 );

已创建 1 行。

SQL> commit;

提交完成。

SQL> alter system enable distributed recovery;

系统已更改。

此时,查询dba_2pc_pending发现已有该事务,并且状态是我们模拟出的prepared状态

SQL> select * from dba_2pc_pending;

LOCAL_TRAN_ID GLOBAL_TRAN_ID STATE MIX A TRAN_COMMENTFAIL_TIME FORCE_TIME RETRY_TIME OS_USER

OS_TERMINAL HOST DB_USER

COMMIT#

----------------

72.0.1608712 XXXXXXX.12345.1.2.3 prepared no12-11 月-08 12-11月-08

此时我们结束这个事务

SQL> COMMIT FORCE '72.0.1608712';

提交完成。

再次查询dba_2pc_pending,发现事务是forced commit状态,该事务已经结束。

SQL> select * from dba_2pc_pending;

LOCAL_TRAN_ID GLOBAL_TRAN_ID STATE MIX A TRAN_COMMENTFAIL_TIME FORCE_TIME RETRY_TIME OS_USER

OS_TERMINAL HOST DB_USER COMMIT#

----------------

72.0.1608712 XXXXXXX.12345.1.2.3 forced commit no12-11 月-08 12-11月-08 12-11月-08

通过x$kutxe 查询事务信息,发现事务释放了回滚段,事务已经结束。

SQL> SELECT KTUXEUSN, KTUXESLT, KTUXESQN, /* Transaction ID */

2 KTUXESTA Status,

3 KTUXECFL Flags

4 FROM x$ktuxe

5 WHERE ktuxesta!='INACTIVE'

6 AND ktuxeusn= 72;

未选定行

此时,我们需要清除dba_2pc_pending中分布式事务的残余信息

SQL> alter session set "_smu_debug_mode"=4;  ―― 在session级别设置回滚段处于手工管理模式,如果不设置这个参数,在回滚段自动管理模式下,清除事务信息会报错

会话已更改。

SQL> execute DBMS_TRANSACTION.PURGE_LOST_DB_ENTRY('72.0.1608712');  ――用dbms包清除事务信息

PL/SQL  过程已成功完成。

SQL> select * from dba_2pc_pending;

未选定行

测试访问业务表

SQL> select count(*) from UNITELE.BI_MQSYNC_SOURCE_CONTROL_T1;

COUNT(*)

----------

367

问题解决。

其实,我在另外一个客户处也碰到过类似问题,当时也是报ORA-01591,但是在dba_2pc_pending中可以查到prepared状态的事务,此时只需要commit force结束这个事务,并清除事务信息就可以了。对于上面的案例,我怀疑开发商直接清除了分布式事务信息,但是事务并没有结束,导致锁资源得不到释放报ORA-01591。

总结: ORA-01591 错误一般是由于分布式事务造成的,造成分布式事务失败的原因主要是库之间的网络突然中断,造成两个库中的事务信息不一致,所以会有残余的分布式事务信息。此时,要针对不同的事务状态做不同的处理。同时在遇到棘手的问题时,可以查询metalink,该案例参考metalink文档:NOTE:[@more@]

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/48010/viewspace-1016050/,如需转载,请注明出处,否则将追究法律责任。

相关推荐