暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

分布式事务锁浅析(下篇)

M小小虾米 2021-08-04
1167

        接上篇,有时候我们在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

问题解决!






文章转载自M小小虾米,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论