# XA 事务模式

# XA 是什么

XA 是由 X/Open 组织提出的分布式事务的规范,XA 规范主要定义了 (全局) 事务管理器 (TM) 和 (局部) 资源管理器 (RM) 之间的接口。本地的数据库如 mysql 在 XA 中扮演的是 RM 角色

XA 一共分为两阶段:

第一阶段(prepare):即所有的参与者 RM 准备执行事务并锁住需要的资源。参与者 ready 时,向 TM 报告已准备就绪。 第二阶段 (commit/rollback):当事务管理者 (TM) 确认所有参与者 (RM) 都 ready 后,向所有参与者发送 commit 命令。

目前主流的数据库基本都支持 XA 事务,包括 mysql、oracle、sqlserver、postgre

我们看看本地数据库是如何支持 XA 的:

第一阶段 准备

XA start '4fPqCNTYeSG' -- 开启一个 xa 事务
UPDATE `user_account` SET `balance`=balance + 30,`update_time`='2021-06-09 11:50:42.438' WHERE user_id = '1'
XA end '4fPqCNTYeSG'
XA prepare '4fPqCNTYeSG' -- 此调用之前,连接断开,那么事务会自动回滚
-- 当所有的参与者完成了prepare,就进入第二阶段 提交
xa commit '4fPqCNTYeSG'

# XA 实战

我们来完成一个完整的 XA,我们先看一个成功的 XA 时序图:

xa_normal

# HTTP 接入示例

gid := dtmcli.MustGenGid(dtmutil.DefaultHTTPServer)
	err := dtmcli.XaGlobalTransaction(dtmutil.DefaultHTTPServer, gid, func(xa *dtmcli.Xa) (*resty.Response, error) {
		resp, err := xa.CallBranch(&busi.TransReq{Amount: 30}, busi.Busi+"/TransOutXa")
		if err != nil {
			return resp, err
		}
		return xa.CallBranch(&busi.TransReq{Amount: 30}, busi.Busi+"/TransInXa")
	})
app.POST(BusiAPI+"/TransInXa", dtmutil.WrapHandler2(func(c *gin.Context) interface{} {
	return dtmcli.XaLocalTransaction(c.Request.URL.Query(), BusiConf, func(db *sql.DB, xa *dtmcli.Xa) error {
		return AdjustBalance(db, TransInUID, reqFrom(c).Amount, reqFrom(c).TransInResult)
	})
}))
app.POST(BusiAPI+"/TransOutXa", dtmutil.WrapHandler2(func(c *gin.Context) interface{} {
	return dtmcli.XaLocalTransaction(c.Request.URL.Query(), BusiConf, func(db *sql.DB, xa *dtmcli.Xa) error {
		return AdjustBalance(db, TransOutUID, reqFrom(c).Amount, reqFrom(c).TransOutResult)
	})
}))

详细例子代码参考 dtm-examples:可以通过以下命令运行这个示例:

go run main.go http_xa

上面的代码首先注册了一个全局 XA 事务,然后添加了两个子事务 TransOut、TransIn。子事务全部执行成功之后,提交给 dtm。dtm 收到提交的 xa 全局事务后,会调用所有子事务的 xa commit,完成整个 xa 事务。

# 失败回滚

如果有一阶段 prepare 操作失败,那么 dtm 会调用各子事务的 xa rollback,进行回滚,最后事务成功回滚。

我们在上述 XaFireRequest 的请求负荷中,传递 TransInResult=FAILURE,让他失败

req := &busi.TransReq{Amount: 30, TransInResult: "FAILURE"}

失败的时序图如下:

xa_rollback

# 注意点

  • dtm 的 XA 事务接口在 v1.13.0 做了一次变更,大幅简化了 XA 事务的使用,整体上与 TCC 的接口保持一致,更易于上手。
  • XA 事务的第二阶段处理,即分支的最终提交或回滚,也会发往 API BusiAPI+"/TransOutXa" ,在这个服务的内部, dtmcli.XaLocalTransaction 会自动做 xa commit | xa rollback , 此时请求的 body 为 nil,因此解析 body 之类的操作,如前面的 reqFrom 需要放在 XaLocalTransaction 内部,否则会解析 body 出错.

# XA 事务的特点:

  • 简单易理解
  • 开发较容易,回滚之类的操作,由底层数据库自动完成
  • 对资源进行了长时间的锁定,并发度低,不适合高并发的业务
更新于 阅读次数

请我喝[茶]~( ̄▽ ̄)~*

PPYYLEE 微信支付

微信支付

PPYYLEE 支付宝

支付宝

PPYYLEE 贝宝

贝宝