接上篇,有时候我们在commit或者rollback分布式事务时,由于无法正常的清除分布式事务的信息会出现如下经典错误:
ORA-02058: no prepared transaction found with ID 10.21.587113
或者在alter日志中发现如下错误:
ORA-01591: lock held by in-doubt distributed transaction 10.21.587113
通过查询分布式视图,发现并没有结果:
SQL> select * from dba_2pc_pending;
但是我们通过报错信息清楚的看到事务号为10.21.587113,该事务在10号回滚段的21号事务槽上并且序列号是587113,这时查询基表x$ktuxe,看看10号回滚段上是否有该事务。
检查本地回滚段
SQL> SELECT KTUXEUSN, KTUXESLT, KTUXESQN, * Transaction ID */ KTUXESTA Status, KTUXECFL Flags FROM x$ktuxe WHERE ktuxesta!='INACTIVE' AND ktuxeusn= 10;(回滚段编码)
KTUXEUSN KTUXESLT KTUXESQN STATUS FLAGS
---------- ---------- ---------- -------------------- ------------
10 21 587113 PREPARED SCO|COL|REV|DEAD|EXTDTX
通过x$ktuxe这个基表,我们看到确实存在这个事务,而且是prepared状态。
产生这个问题的原因:当一个分布式事务死掉时,由于该事务没有正常结束,导致事务持有的锁一直没有释放,所以在访问这个事务涉及的资源时,申请不到锁资源,所以报ORA-01591。由于是分布式事务,当在dba_2pc_pending中查询不到事务信息时,我们是无法通过commit或者rollback结束该事务。
所以,我们目前的任务是模拟出这个分布式事务。由于dba_2pc_pending试图是依赖于pending_trans$这个表,同时事务是与session关联在一起的,所以我们需要手工往pending_trans$和pending_sessions$两个表中插入数据。
SQL> alter system disable distributed recovery;
System altered.
SQL> 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.21.587113',
306206,
'XXXXXXX.12345.1.2.3',
'prepared',
'P',
hextoraw('00000001'),
hextoraw('00000000'),
0,
sysdate,
sysdate);
SQL>insert into pending_sessions$
values
('10.21.587113',
1,
hextoraw('05004F003A1500000104'),
'C',
0,
30258592,
'',
146);
SQL> commit;
SQL> alter system enable distributed recovery;
System altered.
查询dba_2pc_pending发现已有该事务,并且状态是我们模拟出的prepared状态,此时我们提交或者回滚这个事务
SQL> commit force '10.21.587113';
再次产看dba_2pc_pending视图,发现状态已经变成commit force或rollback force状态。并通过x$kutxe 查询事务信息,发现事务释放了回滚段,事务已经结束。
最后,我们用dbms包清除残留的事务信息
SQL> execute DBMS_TRANSACTION.PURGE_LOST_DB_ENTRY('10.21.587113');
再次查看dba_2pc_pending视图,分布式事务信息已经清除。
SQL> select * from dba_2pc_pending;
no rows selected
问题解决!




