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

MySQL-XA事务(二)源码实现

MySQLLabs 2019-08-14
7571



MySQL-XA事务简介请看MySQL-XA事务(一)简介,本文从源码角度,分析XA事务的实现逻辑,文章中忽略了大部分RM的实现细节,比如,redo日志如何写入,如何落盘,如何加行锁,如何更新数据页等等。



01-XA事务涉及到的数据结构 


1. 对应6个命令操作(xa start/begin,end,prepare,commit,rollback,recover)的类,如下:

  • Sql_cmd_xa_start

  • Sql_cmd_xa_end

  • Sql_cmd_xa_prepare

  • Sql_cmd_xa_commit

  • Sql_cmd_xa_rollback

  • Sql_cmd_xa_recover

这六个类是完成XA事务命令的操作入口,是对接口Sql_cmd的具体实现,MySQL XA事务的控制都是通过这6个类来完成的。

2. XA事务状态类XID_STATE,主要包含如下成员:

  • xa_states xa_state 表示事务状态,有如下类型:

enum xa_states {XA_NOTR=0, XA_ACTIVE, XA_IDLE, XA_PREPARED, XA_ROLLBACK_ONLY};
  • static const char *xa_state_names[] 对应5种状态的字符串(NON-EXISTING,ACTIVE,IDLE,PREPARED,ROLLBACK ONLY),在返回错误时,方便客户端阅读。

  • XID m_xid XA事务的唯一标示

  • bool in_recovery recovery的状态标示

  • uint rm_error 资源管理器RM通过此数据向事务管理器TM汇报错误。

  • bool m_is_binlogged 标示XA事务的二进制日志记录情况。在恢复阶段需要用到.


关于XA事务状态的转换,可以参看MySQL-XA事务(一)简介

3. xa_option_words

表示xa命令的可选项,目前xa start/end/prepare都是不支持可选项的,只有xa commit支持ONE PHASE。

enum xa_option_words {XA_NONE, XA_JOIN, XA_RESUME, XA_ONE_PHASE,
XA_SUSPEND, XA_FOR_MIGRATE};


4. xid_t

标示一个唯一的XA事务。

typedef struct xid_t XID

定义了XID的数据格式,主要成员如下:

/**
-1 means that the XID is null
*/

long formatID;

/**
value from 1 through 64
*/

long gtrid_length;

/**
value from 1 through 64
*/

long bqual_length;

/**
distributed trx identifier. not \0-terminated.
*/

char data[XIDDATASIZE];


5. 其它相关类

class THD
class Transaction_ctx
... //太多,不一一列举了


  02 XA事务处理源码分析

 


1. xa start过程详解

xa start命令主要作用是启动一个XA事务,并且把事务状态从XA_NOTR设置为XA_ACTIVE状态。


xa start阶段的函数调用关系如下:

在开启XA事务前,会做如下检测,对应时序图中的步骤3

1. 如果XA {START|BEGIN} xid [JOIN|RESUME]最后的选项不为XA_NONE,则报错XA选项错误,代码如下:

/* TODO: JOIN is not supported yet. */
if (m_xa_opt != XA_NONE)
my_error(ER_XAER_INVAL, MYF(0));

客户端收到报错如下:

mysql> xa start 'trx1' join;
ERROR 1398 (XAE05): XAER_INVAL: Invalid arguments (or unsupported command)
mysql> xa start 'trx1' resume;
ERROR 1398 (XAE05): XAER_INVAL: Invalid arguments (or unsupported command)

2. 如果通过XA命令开启事务时,当前XA事务状态不为XA_NOTR,则报错,代码如下:

else if (!xid_state->has_state(XID_STATE::XA_NOTR))
my_error(ER_XAER_RMFAIL, MYF(0), xid_state->state_name());

客户端报错如下:

//具体报错状态,依赖于当前线程的所处的事务状态。但是错误号是一致的。#define ER_XAER_RMFAIL 1399
ERROR 1399 (XAE07): XAER_RMFAIL: The command cannot be executed when global transaction is in the ACTIVE state

3. 如果通过XA start启动XA事务时,事务处于活跃的非XA事务上下文中,则会报错,代码如下:

else if (thd->locked_tables_mode || thd->in_active_multi_stmt_transaction())
my_error(ER_XAER_OUTSIDE, MYF(0));

客户端报错如下:

mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql>
insert into t1(name) values('aaa');
Query OK, 1 row affected (0.00 sec)

//#define ER_XAER_OUTSIDE 1400
mysql> xa start 'trx1';
ERROR 1400 (XAE09): XAER_OUTSIDE: Some work is done outside global transaction

随后通过调用XID_STATE::start_normal_xa(xid_t const\*)开启xa事务,主要是设置xid_state中的成员变量,对应时序图中的步骤5,如下:

void start_normal_xa(const XID *xid)
{
DBUG_ASSERT(m_xid.is_null());
xa_state= XA_ACTIVE; //状态变更
m_xid.set(xid); //设置xid
in_recovery= false; //recovery状态置为false
rm_error= 0; //资源管理器错误置0
}

通过调用transaction_cache_insert,插入到事务hash缓存表中,对应时序图中的步骤6,在transaction_cache_insert处理过程中,如果存在重复,则报错,检测逻辑如下:

bool transaction_cache_insert(XID *xid, Transaction_ctx *transaction)
{
mysql_mutex_lock(&LOCK_transaction_cache);//加锁
if (my_hash_search(&transaction_cache, xid->key(),
xid->key_length())) //搜索
{
mysql_mutex_unlock(&LOCK_transaction_cache);//冲突,解锁
my_error(ER_XAER_DUPID, MYF(0));//冲突,报错
return true;
}
bool res= my_hash_insert(&transaction_cache,//无冲突,插入 (uchar*)transaction);
mysql_mutex_unlock(&LOCK_transaction_cache);//解锁
return res;
}

客户端报错内容如下:

mysql> xa start 'trx1';
ERROR 1440 (XAE08): XAER_DUPID: The XID already exists


2. XA事务数据更新

在AP操作RMS进行数据写入前,RMS需要向TM注册,见时序图中的步骤12,19,并且后注册的RM在prepare阶段会先被调用。

这里只说明一点:

XA事务中,AP直接访问RM去进行数据更新,在数据更新失败后(RM-innobase),如果innodb参数innodb_rollback_on_timeout为on,则会更新xa_state中的rm_error,用来通知TM发生错误。


3. xa end操作详解


xa end命令主要是结束一个xa事务操作,并将xa事务状态从XA_ACTIVE置为XA_IDLE,或者是XA_ROLLBACK_ONLY,这取决于Innodb参数设置innodb_rollback_on_timeout,在开启innodb_rollback_on_timeout时,如果事务操作(dml)出现锁超时,死锁等情况,xa end操作将会将XA事务状态置为XA_ROLLBACK_ONLY。

XA end操作的函数调用关系如下:

mysql_execute_command(THD*, bool)
    Sql_cmd_xa_end::execute(THD*)
        Sql_cmd_xa_end::trans_xa_end(THD*)
            check...//各种异常检测
            xid_state->set_state(XID_STATE::XA_IDLE);

正常情况下,xa end是将XA事务状态从从XA_ACTIVE置为XA_IDLE。下面讨论对于异常的处理情况,对应时序图中的步骤26。

1.  异常情况:xa end命令不可以附加任何选项,否则报错,代码如下

xa end命令不可以附加任何选项,否则报错,代码如下:

if (m_xa_opt != XA_NONE)
    my_error(ER_XAER_INVAL, MYF(0));

客户端收到报错如下:

mysql> xa end 'trx1' SUSPEND;
ERROR 1398 (XAE05): XAER_INVAL: Invalid arguments (or unsupported command)

2. 执行xa end命令时,xa事务状态必须为XA_ACTIVE,否则报错,代码如下:

else if (!xid_state->has_state(XID_STATE::XA_ACTIVE))
    my_error(ER_XAER_RMFAIL, MYF(0), xid_state->state_name());

客户端收到报错如下:

mysql> xa end 'trx1';
ERROR 1399 (XAE07): XAER_RMFAIL: The command cannot be executed when global transaction is in the IDLE state
mysql> xa prepare 'trx1';
Query OK, 0 rows affected (0.02 sec)
mysql> xa end 'trx1';
ERROR 1399 (XAE07): XAER_RMFAIL: The command cannot be executed when global transaction is in the PREPARED state
mysql> xa commit 'trx1';
Query OK, 0 rows affected (0.02 sec)

mysql> xa end 'trx1';
ERROR 1399 (XAE07): XAER_RMFAIL: The command cannot be executed when global transaction is in the NON-EXISTING state

3. 检测用户输入的xid是否为当前事务上下文中的xid,如果不匹配,报错。代码如下:

else if (!xid_state->has_same_xid(m_xid))
    my_error(ER_XAER_NOTA, MYF(0));

客户端收到报错如下:

mysql> xa start 'trx1';
Query OK, 0 rows affected (0.00 sec)

mysql>
insert into t1(name) values('aa');
Query OK, 1 row affected (0.00 sec)

mysql>
xa end 'trx2';
ERROR 1397 (XAE04): XAER_NOTA: Unknown XID

4. 检测事务是否被标志为回滚,如果是的话,需要更新XA事务状态为XA_ROLLBACK_ONLY。代码如下:

    bool XID_STATE::xa_trans_rolled_back()
    {
    DBUG_EXECUTE_IF("simulate_xa_rm_error", rm_error= true;);
    if (rm_error)
    {
    switch (rm_error) //根据rm_error判断RM错误类型
    {
    case ER_LOCK_WAIT_TIMEOUT: //RM发生锁超时
    my_error(ER_XA_RBTIMEOUT, MYF(0));
    break;
    case ER_LOCK_DEADLOCK: //RM发生死锁
    my_error(ER_XA_RBDEADLOCK, MYF(0));
    break;
    default:
    my_error(ER_XA_RBROLLBACK, MYF(0));
    }
    xa_state= XID_STATE::XA_ROLLBACK_ONLY;
    }


    return (xa_state == XID_STATE::XA_ROLLBACK_ONLY);
    }


    此时客户端会收到报错,并将XA事务状态设置为XA_ROLLBACK_ONLY,事务无法提交,只能回滚,符合参数innodb_rollback_on_timeout设计初衷。客户端报错内容如下:

    mysql> xa start 'trx1';
    Query OK, 0 rows affected (0.00 sec)

    mysql>
    insert into t1(name) values('hhh');
    ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
    mysql> insert into t1(name) values('hhh');
    Query OK, 1 row affected (0.01 sec)

    mysql>
    insert into t1(name) values('hhh');
    Query OK, 1 row affected (0.02 sec)

    mysql>
    xa end 'trx1';
    ERROR 1613 (XA106): XA_RBTIMEOUT: Transaction branch was rolled back: took too long


    3. xa prepare操作详解

    在说明XA事务的prepare操作之前,先来看下,普通事务两阶段提交过程,如下图所示:


    xa prepare阶段与非xa事务的提交流程类似,时序图如下:

    xa prepare命令的主要作用是将事务设置为XA_PREPARE状态,包含xa prepare信息的binlog日志的落盘,innodb日志刷盘(不包含事务prepare标志),innodb中事务prepare,所以这里就存在一个问题,prepare完成后,innodb中事务prepare信息没有落盘。XA prepare主要的函数调用关系如下:

    mysql_execute_command(THD*, bool)
        Sql_cmd_xa_prepare::execute(THD*)
        Sql_cmd_xa_prepare::trans_xa_prepare(THD*)
            check //异常情况检测
            ha_prepare(THD*) //进入XA事务的prepare阶段
            xid_state->set_state(XID_STATE::XA_PREPARED); //设置XA事务状态

    其中异常情况的检测,对应时序图中的步骤30

    1. 判断XA事务状态,如果不是XA_IDLE,则报错

    if (!xid_state->has_state(XID_STATE::XA_IDLE))
        my_error(ER_XAER_RMFAIL, MYF(0), xid_state->state_name());

    客户端收到报错如下:

    mysql> xa start 'trx1';
    Query OK, 0 rows affected (0.00 sec)

    mysql> xa prepare 'trx1';
    ERROR 1399 (XAE07): XAER_RMFAIL: The command cannot be executed when global transaction is in the ACTIVE state

    2. 检测用户输入Xid和当前事务上下文中的Xid是否匹配,如果不匹配,报错,代码如下:

    else if (!xid_state->has_same_xid(m_xid))
        my_error(ER_XAER_NOTA, MYF(0));


    客户端收到报错如下:

    mysql> xa end 'trx1';
    Query OK, 0 rows affected (0.00 sec)

    mysql>
    xa prepare 'trx2';
    ERROR 1397 (XAE04): XAER_NOTA: Unknown XID


    下面来看xa prepare的具体实现过程,此处主要描述与非xa事务的提交过程的区别。XA事务中prepare操作,通过ha_prepare直接调用RM(binlog,innobase)的prepare接口,伪代码如下:

    while (ha_info)
    {
        handlerton *ht= ha_info->ht();
        thd->status_var.ha_prepare_count++;
        if (ht->prepare)
        {
            if (ht->prepare(ht, thd, true)) //调用RM的prepare函数
            {
                ha_rollback_trans(thd, true);
                error=1;
                break;
            
            }
            else
            {
                push_warning_printf(thd, Sql_condition::SL_WARNING,
                ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
                ha_resolve_storage_engine_name(ht));
            }
            ha_info= ha_info->next();
    }

    此时会先调用binlog_prepare(和注册先后顺序有关,后注册的先调用),对应时序图中的步骤33,binlog_prepare的具体实现如下:

    static int binlog_prepare(handlerton *hton, THD *thd, bool all)
    {
    DBUG_ENTER("binlog_prepare");
    if (!all) //此处是XA事务的prepare阶段,无需更新此事务的last_committed,此值和MySQL多线程回放相关,不做过多说明。
    {
        Logical_clock& clock= mysql_bin_log.max_committed_transaction;
        thd->get_transaction()->
        store_commit_parent(clock.get_timestamp());
    }

    DBUG_RETURN(all && is_loggable_xa_prepare(thd) ?
    mysql_bin_log.commit(thd, true) : 0); //在XA事务中会调用mysql_bin_log.commit(thd, true),普通事务直接退出。
    }

    调用mysql_bin_log.commit(thd, true)相当于直接进入了2pc的第二个阶段,也就是commit阶段,对应时序图中的步骤34-36,这是和非XA事务进入此阶段的处理是不同的,伪代码&&分析如下:

    TC_LOG::enum_result MYSQL_BIN_LOG::commit(THD *thd, bool all)
    {
        binlog_cache_mngr *cache_mngr= thd_get_cache_mngr(thd);
        Transaction_ctx *trn_ctx= thd->get_transaction();
        my_xid xid= trn_ctx->xid_state()->get_xid()->get_my_xid();
        bool skip_commit= is_loggable_xa_prepare(thd);//此处skip_commit为true,ordered_commit函数中会利用这个变量跳过关于innodb层的提交处理,因为xa prepare过程是不能在innobase中进行事务提交的。
        XID_STATE *xs= thd->get_transaction()->xid_state();
        err= cache_mngr->trx_cache.finalize(thd, &end_evt, xs);//写入xa end/prepare log event
        ordered_commit(thd, all, skip_commit)//进入order_commit,2pc的commit阶段,非XA事务不会进入到这个逻辑。
    }

    随后进入MYSQL_BIN_LOG::ordered_commit(THD*, bool, bool)的处理,对应时序图中的步骤36-49之间。这部分逻辑主要分为三个部分,flush,sync,commit,伪代码如下:

    MYSQL_BIN_LOG::ordered_commit(THD*, bool, bool)
    {
        //flush stage
        {
            innobase_flush_logs(); //innobase事务日志刷盘,步骤36
            flush_binlog_cache(); //binlog 缓存刷新到文件,步骤38
            semisync_after_flush_hook();//
        }
        //sync stage
        {
            sync_binlog(); //binlog 落盘,步骤41
            update_binlog_end_pos(); //通知dump线程发送binlog,步骤42,此时binlog日志将开始发送给slave实例。

        }
        //commit stage
        {
        semisync_after_sync_hook(); //调用半同步插件after_sync
        // binlog->commit(); 什么都不做
        //innobase_commit();//跳过.
        semisync_after_commit_hook(); //调用半同步插件after_commit
        }
    }


    再调用innobase_xa_prepare(handlerton*, THD*, bool),更新事务状态。这里需要注意的是,innobase没有把事务日志持久化(历史原因,为了innobase 事务日志的组提交),对应时序图步骤50-54。 

    在RMS prepare结束后,设置XA事务状态为XA_PREPARED,对应步骤56,然后XA prepare阶段结束。


    3. xa commit操作详解

    xa commit命令主要完成XA事务最后的提交动作,分为commit当前事务和commit其它事务。时序图如下:

    主要函数调用关系如下:

      mysql_execute_command(THD*, bool)
      Sql_cmd_xa_commit::execute(THD*)
      Sql_cmd_xa_commit::trans_xa_commit(THD*)
      {
      if (!xid_state->has_same_xid(m_xid))//commit非此事务上下文的XA事务
      {
      //检测当前事务状态,如果不是初始化状态,则报错
      if (!xid_state->has_state(XID_STATE::XA_NOTR))
      {
      my_error(ER_XAER_RMFAIL, MYF(0), xid_state->state_name());


      DBUG_RETURN(true);
      }
      Transaction_ctx *transaction= transaction_cache_search(m_xid);//事务缓存hash表中搜索
      XID_STATE *xs= (transaction ? transaction->xid_state() : NULL); //获取目标事务的状态信息
      res= !xs || !xs->is_in_recovery(); //获取recovery状态
      if (res) //不存在或者in_recovery为false,报错.
      {
      my_error(ER_XAER_NOTA, MYF(0));
      DBUG_RETURN(true);
      }
      ha_commit_or_rollback_by_xid(thd, m_xid, !res);
      {
      innobase_commit_by_xid(handlerton*, xid_t*)//innodb层事务提交。
      do_binlog_xa_commit_rollback(THD*, xid_t*, bool) //写Query_log_event(XA COMMIT X'74727831',X'',1)信息
      MYSQL_BIN_LOG::commit(THD*, bool)
      MYSQL_BIN_LOG::ordered_commit(THD*, bool, bool)//flush,sync,commit。其中commit阶段会省略innodb层的事务提交.
      }

      }
      //以下逻辑为提交当前事务.
      tc_log->commit();//通过事务协调器进行事务提交操作。
      MYSQL_BIN_LOG::commit(THD *thd, bool all)//协调器提交
      do_binlog_xa_commit_rollback(THD*, xid_t*, bool) //写Query_log_event(XA COMMIT X'74727831',X'',1)信息
      MYSQL_BIN_LOG::ordered_commit(THD*, bool, bool)//flush,sync,commit (包括半同步相关的插件调用)
      }

      ordered_commit的过程和prepare阶段类似,主要不同点如下:

      • 此时强制innodb 事务日志(prepared标志)落盘

      • 调用innodb的事务提交逻辑,释放锁等资源。

      提交完成后,会从事务缓存hash表中,将此事务删除,对应时序图中的步骤83。以及XA 事务状态设置为初始化XA_NOTR。


      4.  xa recover操作详解

      xa recover的主要命令是查看处于XA_PREPARED状态的所有XA事务。这个命令的处理过程比较简单,主要函数调用关系:

      mysql_execute_command(THD*, bool)
          Sql_cmd_xa_recover::execute(THD*)
              Sql_cmd_xa_recover::trans_xa_recover(THD*)
                  xs->store_xid_info(protocol, m_print_xid_as_hex);//遍历transaction_cache哈希表,进行保存。

      无论事务是否处于in_recovery状态,都会被列出来。


      5.  xa rollback操作详解

      xa rollback的主要作用是对XA事务进行回滚,包括处于XA_IDLE/XA_PREPARED/XA_ROLLBACK_ONLY三个状态的XA事务。时序图中没有画出回滚的逻辑。

      主要函数调用关系如下:

        mysql_execute_command(THD*, bool)
        Sql_cmd_xa_rollback::execute(THD*)
        Sql_cmd_xa_rollback::trans_xa_rollback(THD*)
        if (!xid_state->has_same_xid(m_xid))
        {
        //处理非当前事务上下文的XA事务
        }
        //回滚当前事务上下文的事务
        check//状态检测
        xa_trans_force_rollback(THD*)
        ha_rollback_trans(THD*, bool)

        XA rollback大体上分为回滚当前事务,和回滚其它事务。如下图:

        5.1 回滚当前事务逻辑

        函数调用关系以及解析如下:

          Sql_cmd_xa_rollback::trans_xa_rollback(THD*)
          xa_trans_force_rollback(THD*)
          error= tc_log->rollback(thd, all);
          MYSQL_BIN_LOG::rollback(THD*, bool)
          do_binlog_xa_commit_rollback(THD*, xid_t*, bool)
          {
          if (!xid_state->is_binlogged())
          return 0; //如果无binlog写入,所以回滚的时候也不需要对binlog进行处理。一般是XA_IDLE状态的事务。
          //如下为对处于XA_PREPARED状态的事务回滚操作,处于XA_PREPARED状态的事务binlog日志可能已经发送给了slave,所以需要写入rollback 信息通知slave进行事务回滚。
          char buf[XID::ser_buf_size];
          char query[(sizeof("XA ROLLBACK")) + 1 + sizeof(buf)];
          int qlen= sprintf(query, "XA %s %s", commit ? "COMMIT" : "ROLLBACK",
          xid->serialize(buf));
          Query_log_event qinfo(thd, query, qlen, false, true, true, 0, false);
          return mysql_bin_log.write_event(&qinfo);
          }
          if(新写入了binlog日志) //对应XA_PREPARED状态的事务回滚
          {
          error= ordered_commit(thd, all, /* skip_commit */ true); //通过ordered_commit进行binlog的提交,通知dump线程发送等。
          }
          ha_rollback_low(THD*, bool) //通过handlerton functions去调用回滚,binlog端应该不会做什么了
          {
          binlog_rollback(handlerton*, THD*, bool) //进入binlog rollback的实现
          {
          int error= 0;
          if (thd->lex->sql_command == SQLCOM_ROLLBACK_TO_SAVEPOINT)
          error= mysql_bin_log.rollback(thd, all);
          DBUG_RETURN(error);
          }
          innobase_rollback(handlerton*, THD*, bool)//进入innobase的rollback实现
          {
          trx_rollback_for_mysql(trx_t*)
          trx_rollback_low(trx_t*) //innobase内部事务回滚
          }
          }
          cleanup_trans_state(THD*)
          transaction_cache_delete(Transaction_ctx*) //从事务缓存hash表中删除

          5.2 回滚其他事务逻辑

          回滚非当前XA事务的逻辑如下:

            mysql_execute_command(THD*, bool)
            Sql_cmd_xa_rollback::execute(THD*)
            Sql_cmd_xa_rollback::trans_xa_rollback(THD*)
            {
            XID_STATE *xid_state= thd->get_transaction()->xid_state();
            if (!xid_state->has_same_xid(m_xid)) //回滚的是非当前事务
            {
            if (!xid_state->has_state(XID_STATE::XA_NOTR)) //当前事务上下文不为初始化状态,则报错
            {
            my_error(ER_XAER_RMFAIL, MYF(0), xid_state->state_name());
            DBUG_RETURN(true);
            }
            if (!xs || !xs->is_in_recin_recoveryoin_recoveryvery())
            { //事务处于非recovery状态,也就是in_recovery=false,则报错.
            my_error(ER_XAER_NOTA, MYF(0));
            DBUG_RETURN(true);
            }
            ha_commit_or_rollback_by_xid(thd, m_xid, false)
            {
            xarollback_handlerton(THD*, st_plugin_int**, void*)
            {
            innobase_rollback_by_xid(handlerton*, xid_t*)
            innobase_rollback_trx(trx_t*)//innodb中事务回滚
            binlog_xa_rollback(handlerton*, xid_t*)
            binlog_xa_commit_or_rollback(THD*, xid_t*, bool) //binlog 回滚
            {
            do_binlog_xa_commit_rollback(THD*, xid_t*, bool) //写回滚日志,"XA ROLLBACK X'74727831',X'',1"
            MYSQL_BIN_LOG::rollback(THD*, bool)
            {
            MYSQL_BIN_LOG::ordered_commit(THD*, bool, bool) //flush/sync/commit
            }
            }
            }

            }


            }
            }

            6. XA事务是如何处于in_recovery状态的?

            当处于XA_PREPARED状态的事务线程退出时,mysqld内部会进行如下操作:

              THD::release_resources()
              THD::cleanup()
              //对于处于XA_PREPARED状态的事务,会进行事务状态信息的更改,重新插入
              if (trn_ctx->xid_state()->has_state(XID_STATE::XA_PREPARED))
              {
              transaction_cache_detach(trn_ctx);
              my_hash_delete(&transaction_cache, (uchar *)transaction);
              create_and_insert_new_transaction(xid_t*, bool)
              {
              XID_STATE::start_recovery_xa(xid_t const*, bool)
              {
              xa_state= XA_PREPARED;
              m_xid.set(xid);
              in_recovery= true;
              rm_error= 0;
              m_is_binlogged= binlogged_arg;
              }
              return my_hash_insert(&transaction_cache, (uchar*)transaction); //重新插入
              }
              }
              else //否则,直接删除掉
              {
              xs->set_state(XID_STATE::XA_NOTR);
              trans_rollback(this);
              transaction_cache_delete(trn_ctx);
              }


              在下篇文章中,会描述MySQL-5.7版本xa事务与MySQL-5.6版本的区别,以及目前在使用过程中还面临的问题等,欢迎订阅。


              继续阅读

              MySQL-XA事务(一)简介



              本文分享自微信公众号 - MySQLLabs,如有侵权,请联系 service001@enmotech.com 删除。
              最后修改时间:2019-12-20 11:49:14
              文章转载自MySQLLabs,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

              评论