oracle-如何处理分布式事务报错distribute transation-ORA-1591 ORA-02058

简介:

分布式事务

分布式事务,简单来说,是指一个事务在本地和远程执行,本地需要等待确认远程的事务结束后,进行下一步本地的操作。

如通过dblink update远程数据库的一行记录,如果在执行过程中网络异常,或者其他事件导致本地数据库无法得知远程数据库的执行情况,此时就会发生in doublt的报错。

此时需要dba介入,且需要分多种情况进行处理。

分布式事务在commit提交时候,会经历3个阶段:

1.PREPARE PHASE
2.COMMIT PHASE
3.FORGET PHASE

分布式事务的依次状态及处理:

phase       local_state    remote_state       action
----------- ---------- ------------------  -------------------
prepare     collecting       /              本地DBMS_TRANSACTION.PURGE_LOST_DB_ENTRY
            prepared         /              本地rollback force后PURGE_LOST_DB_ENTRY
 
commit      prepared        commited        本地commit force后本地和远程均PURGE
            commited        commited        本地和远程均PURGE_LOST_DB_ENTRY
            
forget      commited         /              本地PURGE_LOST_DB_ENTRY

两个重要的视图

DBA_2PC_PENDING:列出所有的悬而未决的事务﹐此视图在末填入悬而未决的事务之前是空的﹐解决这后也被清空。

LOCAL_TRAN_ID

本地事务标识﹐格式为integer.integer.ingeger。
当一个连接的local_tran_id和global_tran_id相同时﹐那么该节点是该事务的全局协调器。

GLOBAL_TRAN_ID

全局事务标识,格式为﹕global_db_name.db_hex_id.local_tran_id,其中db_hex_id是用来标识数据库八字符的十六进制数﹐公共事各id在分布式事务的每个节点都是相同的。
“YES”意味着一部分事务已经在一个节点上提交﹐而在另一个节点上被回滚。

TRAN_COMMENT

事务的注释﹐或者如果使用了事务命名﹐当事各被提交时﹐事务的名字就会出现在此处
已提交的事务的全局提交数

DBA_2PC_PENDING的STATE列的说明

- Connecting 
    通常情况下﹐只有全局协调器和本地协调器才使用这个条目﹐节点在能够决定它是否能够准备好之前﹐要收集来自于其它数据库服务的信息。
    节点已准好﹐可能或者也可能没有将已准备好的消息通知本地协调器﹐但此时﹐该节点还没有接收到提交的请求﹐仍保持着准许备好的状态﹐控制着提交事务所必需的任何本地资源。
    节点(任何类型)已经提交了事务﹐但该事务所包含的其它节点可能并没有提交﹐也就是该事务在一个个或多个其它节点上仍然是悬而未决 。
- Forced commit
    DBA进行判断后﹐可以强行提交未决的事务﹐如果一个事务由DBA在本地节点进行手动提交时﹐产生此项目
- Forced abor(rollback)
    DBA进行判断后﹐可以强行回滚未决的事务﹐如果一个事务由DBA在本地节点进行手动回滚时﹐产生此项目

DBA_2PC_NEIGHBORS:列出所有获得的(从远程客户)和送出的(给远程服务器)悬而未决的事务﹐也表示该本地节点是不是事务的提交点站点。

LOCAL_TRAN_ID

对获得事务来说指本地节点信息的客户数据库的名称﹔对送出的事务来说指用于访问远程服务器上信息的数据库链接的名称

DBuser_owner

对获得事务来说指远程数据库链接用于连接的本地账户﹔对于送出事务来说指该数据库链接的拥有者。

INTERFACE

- ‘C’代表提交信息﹐’N’表示已准备好状态的一条消息或是一条请求只读提交的请求。
- 当’IN_OUT’为OUT时﹐’C’表示该连接的远程的站点是提交点站点,并且知道是提交还是中断。’N’表示本地节点正在通知远程节点﹐说它已准备好。 
- 当’IN_OUT’为IN时﹐‘C’表示本地节点或送出的远程的一个数据库是提交点站点﹐’N’表示本地节点正在通知远程节点﹐说它已准备好。


set line 300
COLUMN DATABASE format a22
COLUMN global_tran_id format a25
COLUMN global_name format a22
          
SELECT LOCAL_TRAN_ID, IN_OUT,INTERFACE, DATABASE FROM DBA_2PC_NEIGHBORS;
LOCAL_TRAN_ID          IN_OUT INTERFACE DATABASE              
---------------------- ------ --------- ----------------------
3473.12.18272896       in     N                               
3473.12.18272896       out    C         MES_ERP               


SELECT LOCAL_TRAN_ID, GLOBAL_TRAN_ID,to_char(FAIL_TIME,'dd-mon-yyyy HH24:MI:SS'),STATE, MIXED FROM DBA_2PC_PENDING; 
LOCAL_TRAN_ID          GLOBAL_TRAN_ID            TO_CHAR(FAIL_TIME,'DD-MON-YYYYHH24:MI:SS') STATE            MIXED
---------------------- ------------------------- ------------------------------------------ ---------------- -----
3473.12.18272896       MESPROD.712fc414.3473.12. 06-3月 -2022 12:55:33                       prepared         no   

具体如下:

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阶段结束。
  • 如果数据库在此阶段出现问题,我们查询(假设远程数据库为commit point site,且本地数据库为Global Coordinator):

场景1:

  • 本地:

    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 ' ) ;
    commit;

场景2:

  • 本地:

    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 ' ) ;
    commit;

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。
  • 如果数据库在此阶段出现问题,我们查询

场景1:

  • 本地:

    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 ' ) ;
    commit;
    远程:
    execute DBMS_TRANSACTION . PURGE_LOST_DB_ENTRY ( ' local_tran_id ' ) ;
    commit;

场景2:

  • 本地:

    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 ' ) ;
    commit;
    远程:
    execute DBMS_TRANSACTION . PURGE_LOST_DB_ENTRY ( ' local_tran_id ' ) ;
    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清除分布式事务信息。
  • 此时如果出现问题,我们查询:

    • 本地:
    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 ' ) ;
    commit;

以下特殊情况,仅供参考

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

情况1: 在dba_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且状态是active的transaction:
          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: 这种情况比较少见,在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 ;
     (注:如果使用 auto 的 undo 管理方式,需要执行此步骤,此步骤能避免在后续执行 purge_lost_db_entry 出现 ORA - 01453 的报错,详细信息可见 Bug 2191458 )

      commit ; 

      exec dbms_transaction . purge_lost_db_entry ( ' 1.92.66874 ' )
      

参考:

Managing Distributed Transactions:
https://docs.oracle.com/cd/E11882_01/server.112/e25494/ds_txnman.htm#ADMIN032
MOS:Primary Note for Troubleshooting Oracle Managed Distributed Transactions (Doc ID 100664.1)

https://support.oracle.com/epmos/faces/DocumentDisplay?_afrLoop=183196651725678&id=100664.1&_afrWindowMode=0&_adf.ctrl-state=11ni9siudr_293

ORA-01591错误故障处理:

https://blog.csdn.net/roland_wg/article/details/4598647
http://blog.itpub.net/48010/viewspace-1016050/
https://www.cnblogs.com/lhrbest/p/5738544.html
https://blog.csdn.net/weixin_42298382/article/details/116509942
   
目录
相关文章
|
4月前
|
Oracle 关系型数据库 Java
实时计算 Flink版操作报错之读取Oracle数据库时遇到找不到驱动,是什么原因
在使用实时计算Flink版过程中,可能会遇到各种错误,了解这些错误的原因及解决方法对于高效排错至关重要。针对具体问题,查看Flink的日志是关键,它们通常会提供更详细的错误信息和堆栈跟踪,有助于定位问题。此外,Flink社区文档和官方论坛也是寻求帮助的好去处。以下是一些常见的操作报错及其可能的原因与解决策略。
实时计算 Flink版操作报错之读取Oracle数据库时遇到找不到驱动,是什么原因
|
4月前
|
Oracle 关系型数据库 分布式数据库
PolarDB常见问题之PolarDB(Oracle兼容版) 执行命令报错如何解决
PolarDB是阿里云推出的下一代关系型数据库,具有高性能、高可用性和弹性伸缩能力,适用于大规模数据处理场景。本汇总囊括了PolarDB使用中用户可能遭遇的一系列常见问题及解答,旨在为数据库管理员和开发者提供全面的问题指导,确保数据库平稳运行和优化使用体验。
|
4月前
|
机器学习/深度学习 人工智能 Java
机器学习PAI报错问题之跑collective gpu分布式报错如何解决
人工智能平台PAI是是面向开发者和企业的机器学习/深度学习工程平台,提供包含数据标注、模型构建、模型训练、模型部署、推理优化在内的AI开发全链路服务;本合集将收录PAI常见的报错信息和解决策略,帮助用户迅速定位问题并采取相应措施,确保机器学习项目的顺利推进。
|
2月前
|
机器学习/深度学习 人工智能 Shell
人工智能平台PAI操作报错合集之在分布式训练过程中遇到报错,是什么原因
阿里云人工智能平台PAI是一个功能强大、易于使用的AI开发平台,旨在降低AI开发门槛,加速创新,助力企业和开发者高效构建、部署和管理人工智能应用。其中包含了一系列相互协同的产品与服务,共同构成一个完整的人工智能开发与应用生态系统。以下是对PAI产品使用合集的概述,涵盖数据处理、模型开发、训练加速、模型部署及管理等多个环节。
|
4月前
|
Oracle 关系型数据库 Java
实时计算 Flink版操作报错之报错:Caused by: oracle.jdbc.OracleDatabaseException: ORA-01291如何解决
在使用实时计算Flink版过程中,可能会遇到各种错误,了解这些错误的原因及解决方法对于高效排错至关重要。针对具体问题,查看Flink的日志是关键,它们通常会提供更详细的错误信息和堆栈跟踪,有助于定位问题。此外,Flink社区文档和官方论坛也是寻求帮助的好去处。以下是一些常见的操作报错及其可能的原因与解决策略。
|
4月前
|
Oracle 关系型数据库 MySQL
实时计算 Flink版操作报错之遇到报错 Oracle 19C,如何解决
在使用实时计算Flink版过程中,可能会遇到各种错误,了解这些错误的原因及解决方法对于高效排错至关重要。针对具体问题,查看Flink的日志是关键,它们通常会提供更详细的错误信息和堆栈跟踪,有助于定位问题。此外,Flink社区文档和官方论坛也是寻求帮助的好去处。以下是一些常见的操作报错及其可能的原因与解决策略。
|
4月前
|
Oracle 关系型数据库 MySQL
实时计算 Flink版操作报错合集之采集oracle的时候报ORA-65040:不允许从可插入数据库内部执行该操作如何解决
在使用实时计算Flink版过程中,可能会遇到各种错误,了解这些错误的原因及解决方法对于高效排错至关重要。针对具体问题,查看Flink的日志是关键,它们通常会提供更详细的错误信息和堆栈跟踪,有助于定位问题。此外,Flink社区文档和官方论坛也是寻求帮助的好去处。以下是一些常见的操作报错及其可能的原因与解决策略。
190 3
|
4月前
|
Oracle 关系型数据库 MySQL
实时计算 Flink版操作报错之使用oracle-cdc的,遇到错误:ORA-01292: no log file has been specified for the current LogMiner session,该如何处理
在使用实时计算Flink版过程中,可能会遇到各种错误,了解这些错误的原因及解决方法对于高效排错至关重要。针对具体问题,查看Flink的日志是关键,它们通常会提供更详细的错误信息和堆栈跟踪,有助于定位问题。此外,Flink社区文档和官方论坛也是寻求帮助的好去处。以下是一些常见的操作报错及其可能的原因与解决策略。
|
4月前
|
DataWorks Oracle 关系型数据库
DataWorks操作报错合集之尝试从Oracle数据库同步数据到TDSQL的PG版本,并遇到了与RAW字段相关的语法错误,该怎么处理
DataWorks是阿里云提供的一站式大数据开发与治理平台,支持数据集成、数据开发、数据服务、数据质量管理、数据安全管理等全流程数据处理。在使用DataWorks过程中,可能会遇到各种操作报错。以下是一些常见的报错情况及其可能的原因和解决方法。
77 0
|
1月前
|
Java Nacos Docker
"揭秘!Docker部署Seata遇上Nacos,注册成功却报错?这些坑你不得不防!一网打尽解决秘籍,让你的分布式事务稳如老狗!"
【8月更文挑战第15天】在微服务架构中,Nacos搭配Seata确保数据一致性时,Docker部署Seata后可能出现客户端连接错误,如“can not connect to services-server”。此问题多由网络配置不当、配置文件错误或版本不兼容引起。解决策略包括:调整Docker网络设置确保可达性;检查并修正`file.conf`和`registry.conf`中的Nacos地址和端口;验证Seata与Nacos版本兼容性;修改配置后重启服务;参考官方文档和最佳实践进行配置。通过这些步骤,能有效排除故障,保障服务稳定运行。
36 0

热门文章

最新文章

推荐镜像

更多