mysql java 分布式事务_JAVA架构师之分布式事务解决方案,健康项目实战

背景

在传统架构中可以使用spring的@Transactional 进行声明式或者编程式的事务管理,但如果我们代码中涉及到多数据源操作,就会发现spring的@Transactional事务管理机制会失灵,这种情况下我们就可以考虑使用两阶段提交的解决方案。

我们以mysql为例,mysql在5.0版本后支持了XA规范,也就是支持2PC形式的分布式事务。

mysql XA

相关sql语句

Java 代码

使用druid管理连接池,其支持XA

import com.alibaba.druid.pool.xa.DruidXADataSource;

import com.mysql.jdbc.jdbc2.optional.MysqlXADataSource;

app.properties文件

分析

在这种方案下,我们的代码充当了TM也就是事务资源协调者,而两个不同的数据源mysql充当了RM资源管理着角色,在我们代码中对每个事务的准备情况进行判断,如果都OK则提交事务,如果有没有准备好的则rollback事务.

修改为一个不能正常执行的sql,来查看他的执行过程

format,png

image.png

通过断点分析,我们发现程序在执行到这句的时候就会出现异常,也就是在prepare之前sql语句已经在执行了,只不过我们设置了事务不自动提交,所以在数据库中看不到sql_1的执行结果.

修改正常sql,在prepare阶段加断点

format,png

image.png

我们在数据库中查看事务情况,因为我是在一个数据库服务器上做的的跨库数据源,所以我们能看到两条xa记录

format,png

image.png

我们继续执行到commit语句,放多第一条commit

format,png

image.png

这时候可以发现已经第一个事务的xa信息已经没有了,也就是第一个事务分支已经提交成功了.

format,png

image.png

数据库中可以看到新插入成功了一条数据

format,png

image.png

这是我们尝试修改结构或者插入一条语句,都会发现数据库处于锁定状态

format,png

image.png

等我们把断点放行之后,才可以看到其他语句正常执行,也就是说xa在提交阶段会对数据库进行加锁处理,经过进一步的分析我们发现xa在进入xa end后就对整个表进行加锁操作,因为该sql是update语句,所以在xa end 一直到事务提交或者回滚之前,整个表都处于锁定状态.

format,png

image.png

延伸

我们很容易将这种XA机制扩展到到微服务情况,需要各个微服务提供相应的机制,各个微服务提供对应的prepare接口、commit接口、rollback接口。

缺点

xA的性能问题

XA的性能很低。一个数据库的事务和多个数据库间的XA事务性能对比可发现,性能差10倍左右。因此要尽量避免XA事务,例如可以将数据写入本地,用高性能的消息系统分发数据。或使用数据库复制等技术。只有在这些都无法实现,且性能不是瓶颈时才应该使用XA

这种机制假定prepare ok的事务都可以正常commit

也就是进入prepare返回ok后,在执行commit阶段两个事务就有可能出现一些异常情况,比如第一个正常提交了,但第二个却出现了某种异常失败了。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值