ORA-02055 ORA-02068 ORA-03113 ORA-01591


1.报错如下ORA-02055/02068/03113

Fri Jul  8 13:02:07 2016

Errors in file /oracle/admin/orcl/bdump/orcl_j000_27421.trc:

ORA-12012: 自动执行作业 87 出错

ORA-02055: 分布式更新操作失效;要求回退

ORA-02068: 以下严重错误源于db_orcl

ORA-03113: 通信通道的文件结束

ORA-06512: "shall.Scott_Emp", line 97

ORA-06512: line 1

 

2.报错原因分析

先查看官方对错误代码的解释及建议:

[oracle@zyx ~]$ oerr ora 2055

02055, 00000, "distributed update operation failed; rollback required"

// *Cause: a failure during distributed update operation may not have

//      rolled back all effects of the operation.  Since

//      some sites may be inconsistent, the transaction must roll back to

//      a savepoint or entirely

// *Action: rollback to a savepoint or rollback transaction and resubmit

 

[oracle@zyx ~]$ oerr ora 3113

03113, 00000, "end-of-file on communication channel"

// *Cause: The connection between Client and Server process was broken.

// *Action: There was a communication error that requires further investigation.

//          First, check for network problems and review the SQL*Net setup.

//          Also, look in the alert.log file for any errors. Finally, test to

//          see whether the server process is dead and whether a trace file

//          was generated at failure time.

 

 

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

 

    报错原因应该分两种情况,一种是网络不稳定导致,一种是远端数据库有报错引起

 

2.1 网络问题排查

先根据db_link查找出解析地址

sys@ORCL>select name,HOST,userid from link$;

NAME               HOST    USERID

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

DB_ORCL_LINK.TEST.COM   db_orcl   SHALL

 

/*   查看本地dblink并生成创建语句

SELECT 'CREATE '||DECODE(U.NAME,'PUBLIC','public ')||'DATABASE LINK '||CHR(10)

||DECODE(U.NAME,'PUBLIC',Null, 'SYS','',U.NAME||'.')|| L.NAME||chr(10)

||'CONNECT TO ' || L.USERID || ' IDENTIFIED BY "'||L.PASSWORD||'" USING

'''||L.HOST||''''

||chr(10)||';' TEXT

FROM SYS.LINK$ L, SYS.USER$ U

WHERE L.OWNER# = U.USER#;

*/

 

找到地址后,tnsping看是否连通

[oracle@zyx ~]$ tnsping db_orcl

TNS Ping Utility for Linux: Version 11.2.0.4.0 - Production on 25-APR-2016 13:55:39

Copyright (c) 1997, 2013, Oracle.  All rights reserved.

Used parameter files:

/u01/app/oracle/product/11.2.0/db_1/network/admin/sqlnet.ora

 

Used TNSNAMES adapter to resolve the alias

Attempting to contact (DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.11.22)(PORT = 1521)) (CONNECT_DATA = (SERVER = DEDICATED) (SERVICE_NAME = orcl)))

OK (10 msec)

 

----如果通讯正常,那说明可能不是由于网络问题导致的

 

2.2 远端数据库报错

reference     http://blog.csdn.net/indexman/article/details/9001812

原因:通过数据库链接调用远程存储过程或包。然而,执行过程中远程数据库有报错,但是部分语句已成功执行

措施:在调用端可以查询之前,需要执行回滚操作,否则将获得以上错误提示。

 

问题重现:

----首先创建两个测试用户

sys@ORCL>drop user test1 cascade;

sys@ORCL>drop user test2 cascade;

 

sys@ORCL>create user test1 identified by test1;

sys@ORCL>create user test2 identified by test2;

 

sys@ORCL>grant create session, create table, create trigger, create procedure, create database link to test1, test2;

sys@ORCL>alter user test1 quota unlimited on users;

sys@ORCL>alter user test2 quota unlimited on users;

 

----然后用test2(远端用户登录)连接数据库,然后创建测试表

sys@ORCL>conn test2/test2@orcl

Connected.

test2@ORCL>create table test2_tab(n number);

Table created.

test2@ORCL>insert into test2_tab values(1);

1 row created.

test2@ORCL>commit;

Commit complete.

 

----接下来,为了演示这个错误,在该表上创建一个触发器,并且确定该触发器是失败的。这里,将一个字符赋给一个数字字段

create or replace trigger test2_tab_bir

    before insert on test2_tab

    for each row

begin

  :new.n := 'a';

end;

/

Trigger created.

 

----然后用test1去连接并创建dblink

test2@ORCL>conn test1/test1@orcl

Connected.

test1@ORCL>create database link test2 connect to test2 identified by test2 using 'orcl';

Database link created.

 

----接下来,创建一个存储过程,首先做一个成功的dml,之后一个dml由于不正确的触发而失败

create or replace procedure p_test is

begin

  -- first do a statement that executes ok

  update test2_tab@test2 set n=2;

  -- next statement will fail because of the invalid trigger

  insert into test2_tab@test2 values(1);

end;

/

Procedure created.

 

----然后执行这个存储过程,让它报错

test1@ORCL>exec p_test

BEGIN p_test; END;

*

ERROR at line 1:

ORA-02055: distributed update operation failed; rollback required

ORA-06502: PL/SQL: numeric or value error: character to number conversion error

ORA-06512: at "TEST2.TEST2_TAB_BIR", line 2

ORA-04088: error during execution of trigger 'TEST2.TEST2_TAB_BIR'

ORA-02063: preceding 3 lines from TEST2

ORA-06512: at "TEST1.P_TEST", line 6

ORA-06512: at line 1

 

----现在就出现了一个失败的分布式事务,需要做回滚,否则查询任何表或视图都会报错

test1@ORCL>select sysdate from dual;

select sysdate from dual

                    *

ERROR at line 1:

ORA-02067: transaction or savepoint rollback required

test1@ORCL>select * from test2_tab@test2;

select * from test2_tab@test2

       *

ERROR at line 1:

ORA-02067: transaction or savepoint rollback required

 

----同时发生错误时,oracle调用另一个选择递归(注意ora-00604)

test1@ORCL>select * from user_2pc_pending;

select * from user_2pc_pending

              *

ERROR at line 1:

ORA-00604: error occurred at recursive SQL level 1

ORA-02067: transaction or savepoint rollback required

 

 

test1@ORCL>conn test2/test2@orcl

ERROR:

ORA-02067: transaction or savepoint rollback required

Connected.

test2@ORCL>select * from test2_tab;

         N

----------

         1

 

test2@ORCL>conn test1/test1@orcl

Connected.

test1@ORCL>select * from test2_tab@test2;

         N

----------

         1

 

3.访问某些表特定行时报ORA-01591错误

reference                                              http://www.linuxidc.com/Linux/2014-03/99032.htm

http://blog.csdn.net/roland_wg/article/details/4598647

 

3.1 报错信息

----在访问某些表的特定行时报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 分布式事务

 

3.2 DBA_2PC_PENDING是做什么的?

    Oracle会自动处理分布事务,保证分布事务的一致性,所有站点全部提交或全部回滚。一般情况下,处理过程在很短的时间内完成,根本无法察觉到。但是,如果在commitrollback的时候,出现了连接中断或某个数据库站点CRASH(崩溃)的情况,则提交操作可能会无法继续,此时DBA_2PC_PENDINGDBA_2PC_NEIGHBORS中会包含尚未解决的分布事务。

    对于绝大多数情况,当恢复连接或CRASH数据库重新启动后,会自动解决分布式事务,不需要人工干预。只有分布事务锁住的对象急需被访问,锁住的回滚段阻止了其他事务的使用,网络故障或CRASH的数据库的恢复需要很长的时间等情况出现时,才使用人工操作的方式来维护分布式事务

    手工强制提交或回滚将失去二层提交的特性,Oracle无法继续保证事务的一致性,事务的一致性应由手工操作者保证。

    对于分布式事务,给事务命名是一个好的习惯。而且在事务执行过程中,可以使用ALTER SESSION ADVISE COMMIT/ROLLBACK;语句,为手工解决分布事务提供参考信息。

   

    当手工解决分布事务出现了冲突,比如一个站点进行了提交而另一个进行了ROLLBACK,这时,DBA_2PC_PENDING中的记录不会清除,必须使用DBMS_TRANSACTION.PURGE_MIXED过程来清除。

    如果CRASH的数据库必须重建,或者无法再次启动,则DBA_2PC_PENDING中的记录也无法自动清除,需要使用DBMS_TRANSACTION.PURGE_LOST_DB_ENTRY过程来清除。

   

    Oracle9i中,当使用上述两个过程时,必须处于UNDO_MANAGEMENTMANUAL的模式,这个限制条件Oracle没有写到文档中。一般使用9i都会使用AUTO模式(Oracle也是这样推荐的),也就是说,想要清除DBA_2PC_PENDING中的信息,必须重起数据库两次,感觉这两个过程的实际用处不大。

    出现无法解决的分布式事务时,可能会锁住分布式事务中涉及的表,由于Oracle无法确定哪些数据是提交过的,哪些是没有提交的,无法确定查询操作可见的结果集,因此,即使是查询操作也无法在该表上执行。

 

    使用ALTER SYSTEM DISABLE DISTRIBUTED RECOVERY,可以使Oracle不再自动解决分布事务,即使网络恢复连接或者CRASH的数据库重新启动。ALTER SYSTEM ENABLE DISTRIBUTED RECOVERY恢复自动解决分布事务。

    为了保证数据库之间的SCN同步,可以采用两种方法:在查询数据前,执行SELECT * FROM DUAL@REMOTE或者在执行查询前提交或回滚当前事务。

 

3.3 故障分析

首先,还是看一下官方对错误代码的解释及建议:

[oracle@zyx ~]$ oerr ora 1591

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.

 

    OracleORA-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(怀疑)的报错。

 

    分布式事务的Two-Phase Commit机制,会经历3个阶段:

3.3.1分布式事务PREPARE PHASE(准备阶段):

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

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

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

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

 

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

 

------------>该阶段如何处理?

    如果数据库在此阶段出现问题,我们查询(假设远程数据库为commit point site,且本地数据库为Global Coordinator):

本地:

select local_tran_id,state from dba_2pc_pending

LOCAL_TRAN_ID          STATE

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

2.12.64845              collecting(收集)

远程:

select local_tran_id,state from dba_2pc_pending

no rows selected

    即表示本地数据库要求其他点做好commit或者rollback准备,现在正在收集其他点的数据库的返回信息,但是远程数据库未知状态(in doubt)。我们需要将本地的Global Coordinator的状态清除掉:

execute DBMS_TRANSACTION.PURGE_LOST_DB_ENTRY('local_tran_id');

 

    或者我们在查询的时候发现是如下的状态:

本地:

select local_tran_id,state from dba_2pc_pending

LOCAL_TRAN_ID          STATE

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

2.12.64845             prepared

远程:

select local_tran_id,state from dba_2pc_pending

no rows selected

    即表示本地Global Coordinator已经做好准备,已经将分布式锁放到各个事务的表上,但是远程数据库的状态再次未知(in doubt),我们需要手工的将本地的transaction rollback掉,并且清除分布式事务信息:

本地:

rollback force 'local_tran_id';

execute DBMS_TRANSACTION.PURGE_LOST_DB_ENTRY('local_tran_id');

 

3.3.2分布式事务COMMIT PHASE:

    a. Global Coordinator将最大scn传到commit point site,要求其commit

    b. commit point尝试commit或者rollback。分布式事务锁释放。

    c. commit point通知Global Coordinator已经commit

    d. Global Coordinator通知分布式事务的所有点进行commit

 

------------>该阶段如何处理?

    如果数据库在此阶段出现问题,我们查询

本地:

select local_tran_id,state from dba_2pc_pending

LOCAL_TRAN_ID          STATE

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

2.12.64845             prepared

远程:

select local_tran_id,state from dba_2pc_pending

LOCAL_TRAN_ID          STATE

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

1.92.66874             commited

    即远程数据库可能已经commit,但是本地Global Coordinator未知远程数据库的状态,还是处于prepare的状态。我们需要在如下处理:

本地:

commit force 'local_tran_id';

execute DBMS_TRANSACTION.PURGE_LOST_DB_ENTRY('local_tran_id');

远程:

execute DBMS_TRANSACTION.PURGE_LOST_DB_ENTRY('local_tran_id');

 

    或者我们在查询的时候发现是如下的状态:

本地:

select local_tran_id,state from dba_2pc_pending

LOCAL_TRAN_ID          STATE

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

2.12.64845            commited

远程:

select local_tran_id,state from dba_2pc_pending

LOCAL_TRAN_ID          STATE

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

1.92.66874             commited

    即远程数据库和本地数据库均已经完成commit,但是分布式事务的信息尚未清除,我们需要在本地和远程运行:

本地:

execute DBMS_TRANSACTION.PURGE_LOST_DB_ENTRY('local_tran_id');

远程:

execute DBMS_TRANSACTION.PURGE_LOST_DB_ENTRY('local_tran_id');

 

3.3.3分布式事务FORGET(忘记) PHASE:

    a. 参与的点通知commit point site他们已经完成commitcommit point site就能忘记(forget)这个事务。

    b. commit point site在远程数据库上清除分布式事务信息。

    c. commit point site通知Global Coordinator可以清除本地的分布式事务信息。

    d. Global Coordinator清除分布式事务信息。

 

------------>该阶段如何处理?

    此时如果出现问题,我们查询:

本地:

select local_tran_id,state from dba_2pc_pending

LOCAL_TRAN_ID          STATE

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

2.12.64845            commited

远程:

select local_tran_id,state from dba_2pc_pending

no rows selected

    即远程commit point site已经完成commit,通知Global Coordinator清除本地的分布式事务信息,但是Global Coordinator没有收到该信息。我们需要这样处理:

本地:

execute DBMS_TRANSACTION.PURGE_LOST_DB_ENTRY('local_tran_id');

 

3.3.4确定当前分布式的故障阶段

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

 

3.4 确定故障原因

???——————>>

    我们知道要结束一个事务有两种办法:commitrollback。现在我们尝试结束这个事务:

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 */ KTUXESTA Status, KTUXECFL Flags

     FROM x$ktuxe

       WHERE ktuxesta!='INACTIVE'

          AND ktuxeusn= 72;

KTUXEUSNKTUXESLTKTUXESQN STATUSFLAGS

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

72 01608712 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$两个表中插入数据。

 

3.5 故障处理

3.5.1手工往pending_trans$和pending_sessions$两个表中插入数据

SQL> alter system disable distributed recovery;

系统已更改。 ----关闭分布式恢复

 

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( '72.0.1608712',306206,'XXXXXXX.12345.1.2.3','prepared','P',hextoraw( '00000001' ),

             hextoraw( '00000000' ),0, sysdate, sysdate );

已创建 1 行。

 

SQL> insert into pending_sessions$ values( '72.0.1608712',1,hextoraw ('05004F003A1500000104'),'C', 0, 30258592, '',146);

已创建 1 行。

 

SQL> commit;

提交完成。

 

SQL> alter system enable distributed recovery;

系统已更改。

 

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

SQL> select * from dba_2pc_pending;

LOCAL_TRAN_IDGLOBAL_TRAN_ID STATEMIX A TRAN_COMMENTFAIL_TIMEFORCE_TIME RETRY_TIME OS_USER  OS_TERMINAL HOSTDB_USER   COMMIT#

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

72.0.1608712  XXXXXXX.12345.1.2.3  prepared no 2016-04-25 15:58:05   2016-04-25 16:04:23

 

3.5.2此时我们结束这个事务

SQL> COMMIT FORCE '72.0.1608712';

提交完成。

 

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

SQL> select * from dba_2pc_pending;

LOCAL_TRAN_IDGLOBAL_TRAN_ID STATEMIX A TRAN_COMMENTFAIL_TIMEFORCE_TIME RETRY_TIME OS_USER  OS_TERMINALHOSTDB_USER COMMIT#

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

 

72.0.1608712XXXXXXX.12345.1.2.3  forced commit  no 2016-04-25 15:58:05   2016-04-25 16:04:23

 

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

SQL> SELECT KTUXEUSN, KTUXESLT, KTUXESQN, /* Transaction ID */ KTUXESTA Status, KTUXECFL Flags

     FROM x$ktuxe

       WHERE ktuxesta!='INACTIVE'

          AND ktuxeusn= 72;

未选定行

 

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

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

SQL> alter session set "_smu_debug_mode"=4;

会话已更改。

 

――用dbms包清除事务信息

SQL> execute DBMS_TRANSACTION.PURGE_LOST_DB_ENTRY('72.0.1608712');

PL/SQL 过程已成功完成。

 

SQL> select * from dba_2pc_pending;

未选定行

 

3.5.4最后,测试访问业务表

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

COUNT(*)

----------

 367

 

问题解决。

 

3.5.5故障总结

    在数据库出现ORA-01591时,如果dba_2pc_pending中可以查到prepared状态的事务,此时只需要commit force结束这个事务,并清除事务信息就可以了。对于上面的案例,怀疑开发直接清除了分布式事务信息,但是事务并没有结束,导致锁资源得不到释放报ORA-01591

    ORA-01591错误一般是由于分布式事务造成的,造成分布式事务失败的原因主要是库之间的网络突然中断,造成两个库中的事务信息不一致,所以会有残余的分布式事务信息。

 

 

3.6 :分布式事务处理故障总结

综上,分布式事务的依次状态为:

phase(阶段)       local_state(本地状态)    remote_state(远程状态)     action(处理方法)

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

prepare     collecting       /               本地DBMS_TRANSACTION.PURGE_LOST_DB_ENTRY

             prepared         /              本地rollback forcePURGE_LOST_DB_ENTRY

 

commit    prepared        commited         本地commit force后本地和远程均PURGE

             commited        commited        本地和远程均PURGE_LOST_DB_ENTRY

            

forget      commited         /              本地PURGE_LOST_DB_ENTRY

 

   

    另,当我们遇到使用rollback/commit force的时候,无法正常的清除分布式事务的信息,会报错ORA-02058: no prepared transaction found with ID X.XX.XXXXX时,我们需要通过手工方式来清除该信息。(注,以下方式修改数据字典,存在风险,使用前请备份好你的数据库)

 

例外--情况1:

情况1dba_2pc表中还有事务记录,但是实际已经不存在该事务了:

 

select local_tran_id, state from dba_2pc_pending;

       LOCAL_TRAN_ID          STATE

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

       1.92.66874             prepared

(注:'1.92.66874' 的结构为rbs#, slot#, wrap#,此事务在rollback segment #1

 

我们再用如下语句找出使用rollback segment #1且状态是activetransaction

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

         KTUXESTA Status,

         KTUXECFL Flags

  FROM x$ktuxe

  WHERE ktuxesta!='INACTIVE'

        AND ktuxeusn= 1; <== 这是rollback segment#,即rbs#

  no rows selected

因此我们在rollback force的时候会报错:

ORA-02058: no prepared transaction found with ID 1.92.66874

 

我们需要如下处理:

set transaction use rollback segment SYSTEM;

 

delete from sys.pending_trans$

  where local_tran_id = '1.92.66874';

 

delete from sys.pending_sessions$ where local_tran_id = '1.92.66874';

delete from sys.pending_sub_sessions$ where local_tran_id = '1.92.66874';

commit;

 

例外--情况2:

情况2这种情况比较少见,在dba_2pc表中无法查到分布式事务信息,但是实际上却是存在该分布式事务的:

 

我们在alertlog中可以看到:

ORA-1591: lock held by in-doubt distributed transaction 1.92.66874

我们查询dba_2pc的表,发现没有分布式事务信息:

select local_tran_id, state from dba_2pc_pending

where local_tran_id='1.92.66874';

 no rows selected

 

但是去查实际的rollback segment信息,却发现有prepared状态的分布式事务存在:

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

       KTUXESTA Status,

       KTUXECFL Flags

FROM x$ktuxe

WHERE ktuxesta!='INACTIVE'

      AND ktuxeusn= 1;

  KTUXEUSN   KTUXESLT   KTUXESQN STATUS           FLAGS

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

         1         92      66874 PREPARED         SCO|COL|REV|DEAD

 

我们无法做commit force或者rollback force

rollback force '1.92.66874';

 ORA-02058: no prepared transaction found with ID 1.92.66874

 

我们用如下的方式手工清理:

alter system disable distributed recovery;

 

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( '1.92.66874', /* <== 此处为你的local tran id */

        306206,                  /*                                         */

        'XXXXXXX.12345.1.2.3',   /*  这些值不必更改,   */

        'prepared','P',          /*  是静态参数,可以直接   */

        hextoraw( '00000001' ),  /*  在这个sql中使用                             */

        hextoraw( '00000000' ),  /*                                         */

        0, sysdate, sysdate );

 

insert into pending_sessions$

    values( '1.92.66874',/* <==此处为你的local tran id  */

        1, hextoraw('05004F003A1500000104'),

        'C', 0, 30258592, '',

        146

      );

 

commit;

 

commit force '1.92.66874';

 

此时如果commit force还是出现报错,需要继续执行:

delete from pending_trans$ where local_tran_id='1.92.66874';

delete from pending_sessions$ where local_tran_id='1.92.66874';

commit;

alter system enable distributed recovery;

 

此时如果没有报错,则执行以下语句:

alter system enable distributed recovery;

  and purge the dummy entry from the dictionary, using(从字典中清除虚拟条目,使用)

connect / as sysdba

alter session set "_smu_debug_mode" = 4;

      (注:如果使用autoundo管理方式,需要执行此步骤,此步骤能避免在后续执行purge_lost_db_entry出现ORA-01453 的报错,详细信息可见Bug 2191458

commit; 

exec dbms_transaction.purge_lost_db_entry( '1.92.66874' )

 

 

Symptoms

Symptoms(症状)

While trying to commit or rollback a pending transaction getting error ORA-2058...

Subsequently when trying to purge the pending transactions using the

procedure "dbms_transaction.purge_lost_db_entry" gives the following errors..

 

SQL> EXECUTE DBMS_TRANSACTION.PURGE_LOST_DB_ENTRY('5.23.2386');

 

BEGIN DBMS_TRANSACTION.PURGE_LOST_DB_ENTRY('5.23.2386'); END;

*

ERROR at line 1:

ORA-30019: Illegal rollback Segment operation in Automatic Undo mode

ORA-06512: at "SYS.DBMS_TRANSACTION", line 65

 

SQL> execute DBMS_TRANSACTION.PURGE_LOST_DB_ENTRY('37.16.108');

BEGIN DBMS_TRANSACTION.PURGE_LOST_DB_ENTRY('37.16.108'); END;

*

ERROR at line 1:

ORA-06510: PL/SQL: unhandled user-defined exception

ORA-06512: at "SYS.DBMS_TRANSACTION", line 94

 

Cause(原因)

If the remote database no longer exists then the transaction will have to be

purged from the list of pending distributed transactions.

The transaction to be deleted is in the Prepared State.

Solution(解决方案)

If the command causes an ORA-2058 error to occur, it means that the remote

database cannot be accessed. In this case, check whether the database link to

the remote database exists and whether the remote database is shutdown.

 

If the remote database no longer exists then the transaction will have to be

purged from the list of pending distributed transactions.

 

Follow the instructions on how to purge a

distributed transaction from the database.

=================================

If the remote database cannot be accessed, a failed distributed transaction

cannot be committed or rolled back and so must be purged from the list of

pending transactions.

 

1. Identify the id of the transaction:

 

SQL> SELECT LOCAL_TRAN_ID, GLOBAL_TRAN_ID FROM DBA_2PC_PENDING;

 

2. Purge the transaction:

 

SQL> EXECUTE DBMS_TRANSACTION.PURGE_LOST_DB_ENTRY('');

SQL> COMMIT;

 

3. Confirm that the transaction has been purged:

 

SQL> SELECT LOCAL_TRAN_ID, GLOBAL_TRAN_ID FROM DBA_2PC_PENDING;

 

 

Step 2:

=====

If you get the following errors while purging transactions using "dbms_transaction.purge_lost_db_entry"

 

 

SQL> EXECUTE DBMS_TRANSACTION.PURGE_LOST_DB_ENTRY('5.23.2386');

 

BEGIN DBMS_TRANSACTION.PURGE_LOST_DB_ENTRY('5.23.2386'); END;

*

ERROR at line 1:

ORA-30019: Illegal rollback Segment operation in Automatic Undo mode

ORA-06512: at "SYS.DBMS_TRANSACTION", line 65

ORA-06512: at "SYS.DBMS_TRANSACTION", line 85

 

 

Fix:

===

This problem is logged as

Bug.2191458 (unpublished) UNABLE TO EXEC DBMS_TRANSACTION.PURGE_LOST_DB_ENTRY WITH AUTO UNDO MANAGEMENT

and is worked by development.

 

Use the following Workaround:

 

You have to use local_tran_id.....

 

Issue commit before alter system set "_smu_debug_mode" = 4;

 

Follow the steps,

 

SQL> commit;

SQL> alter session set "_smu_debug_mode" = 4;

SQL> commit;

SQL> execute DBMS_TRANSACTION.PURGE_LOST_DB_ENTRY('local_tran_id');

SQL> commit;

 

Step 3:

=====

 

When executing the following procedure(dbms_transaction.purge_lost_db_entry)

to delete entries from

dba_2pc_pending one encounters the following error:

 

SQL> execute DBMS_TRANSACTION.PURGE_LOST_DB_ENTRY('37.16.108'); ==>For example..

BEGIN DBMS_TRANSACTION.PURGE_LOST_DB_ENTRY('37.16.108'); END;

*

ERROR at line 1:

ORA-06510: PL/SQL: unhandled user-defined exception

ORA-06512: at "SYS.DBMS_TRANSACTION", line 94

 

 

Fix:

===

 

The transaction to be deleted is in the prepared state and has to be either

force committed or force rollback

 

SQL> select LOCAL_TRAN_ID,STATE from dba_2pc_pending;

 

LOCAL_TRAN_ID STATE

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

37.16.108 prepared

 

SQL> rollback force '37.16.108'; ==>For example

 

Rollback complete.

 

SQL> select LOCAL_TRAN_ID,STATE from dba_2pc_pending;

 

LOCAL_TRAN_ID STATE

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

37.16.108 forced rollback

 

SQL> COMMIT;

 

SQL>alter system set "_smu_debug_mode" = 4;

Rollback complete.

 

SQL> exec dbms_transaction.purge_lost_db_entry('37.16.108'); ==>For example

SQL> COMMIT;

 

3.7 脚本:DBA_2PC_PENDING中分布式锁

reference      http://blog.itpub.net/27042095/viewspace-751953/

 

运行shell脚本后,会生成 roll.sql文件。

只需要运行roll.sql就会解除dba_2pc_pending 中的分布式锁。

 

注意:根据情况决定shell脚本中是否需要where 条件,比如过滤status 是prepare的,还是其他的,还是全部的。

 

----------------------shell脚本-------------------------

#!/bin/bash

. /home/oracle/.bash_profile

echo `sqlplus -S  / as sysdba << EOF

set heading off pagesize 0 echo off linesize 200 feedback off trimspool on

select 'rollback force  ''' || LOCAL_TRAN_ID || ''';' || chr(10) ||

'execute DBMS_TRANSACTION.PURGE_LOST_DB_ENTRY(''' || LOCAL_TRAN_ID

 || ''');' || chr(10) || 'commit;' from DBA_2PC_PENDING;

exit;

EOF` >>roll.sql

 

 

------------------------上述sh生成的roll.sql文件格式-----------------------

rollback force  '2.12.64845';

execute DBMS_TRANSACTION.PURGE_LOST_DB_ENTRY('2.12.64845');

commit;

 

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

转载于:http://blog.itpub.net/30130773/viewspace-2122382/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值