快捷搜索:  汽车  科技

一文看懂分布式事务(又问分布式事务)

一文看懂分布式事务(又问分布式事务)JTA 的特点:如果前面出现了错误或是没有提交,那么第二阶段就不会提交,而是直接回滚,这样所有的事务都会做回滚操作。基于 JTA 这种方案实现分布式事务的强一致性。XAResouce:资源管理,通过 Session 来进行事务管理,commit(xid)...XID : 每一个事务都分配一个特定的任务 XID。JTA 主要的原理是2PC(二阶段提交),当整个业务完成了之后只是第一阶段提交,在第二阶段提交之前会检查其他所有事务是否已经提交。

1、强一致性分布式事务(单系统多数据源的情况)

单体架构多数据源,在电商业务开发中,肯定是先执行对订单库的操作,但是不提交事务,再执行对库存库的操作,也不提交事务,如果两个操作都成功,在一起提交事务,如果有一个操作失败,则两个都进行回滚。

单体架构多数据源的情况下,大多使用的是基于2PC/XA协议实现的JTA基于JTA实现的 Jar 包Atomikos

上节我们已经知道了 2PC 和 XA 协议的原理,就是基于 2PC/XA 协议实现的 JTA是 Java 规范,是 XA 在 Java 上的实现。
JTA(Java Transaction Manager):

Transaction Manager:常用方法,可以开启,回滚,获取事务。begin(),rollback()...

XAResouce:资源管理,通过 Session 来进行事务管理,commit(xid)...

XID : 每一个事务都分配一个特定的任务 XID。

JTA 主要的原理是2PC(二阶段提交),当整个业务完成了之后只是第一阶段提交,在第二阶段提交之前会检查其他所有事务是否已经提交。

如果前面出现了错误或是没有提交,那么第二阶段就不会提交,而是直接回滚,这样所有的事务都会做回滚操作。基于 JTA 这种方案实现分布式事务的强一致性。

JTA 的特点:

基于两阶段提交,有可能会出现数据不一致的情况。

事务时间过长,阻塞。

性能低,吞吐量低。

现可以使用基于 JTA 实现的 Jar 包 Atomikos 。

首先看一下Spring原生transaction事务控制的一个过程,如下图:

一文看懂分布式事务(又问分布式事务)(1)

然后在看整JTA Atomikos分布式事务:

1、首先,我们先构建一个事务管理器,Atomikos包下的

@Bean("jtaManger") @Primary public JtaTransactionManager activityTransactionManager() { UserTransactionManager userTransactionManager = new UserTransactionManager(); UserTransaction userTransaction = new UserTransactionImp(); return new JtaTransactionManager(userTransaction userTransactionManager); }

2、创建一个数据库连接,是AtomikosDataSourceBean类型,由Atomikos管理。

@Bean("activityDataSource") @Primary public DataSource activityDataSource() { return DataSourceUtils.getDataSource(dbUrl username password driverClassName initialSize minIdle maxActive maxWait timeBetweenEvictionRunsMillis minEvictableIdleTimeMillis validationQuery testWhileIdle testOnBorrow testOnReturn poolPreparedStatements maxPoolPreparedStatementPerConnectionSize filters connectionProperties "activityDataSource"); }

public class DataSourceUtils { public static DataSource getDataSource(String dbUrl String username String password String driverClassName int initialSize int minIdle int maxActive int maxWait int timeBetweenEvictionRunsMillis int minEvictableIdleTimeMillis String validationQuery boolean testWhileIdle boolean testOnBorrow boolean testOnReturn boolean poolPreparedStatements int maxPoolPreparedStatementPerConnectionSize String filters String connectionProperties String dbName) { DruidXADataSource datasource = new DruidXADataSource(); datasource.setUrl(dbUrl); datasource.setUsername(username); datasource.setPassword(password); datasource.setDriverClassName(driverClassName); datasource.setInitialSize(initialSize); datasource.setMinIdle(minIdle); datasource.setMaxActive(maxActive); datasource.setMaxWait(maxWait); datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis); datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis); datasource.setValidationQuery(validationQuery); datasource.setTestWhileIdle(testWhileIdle); datasource.setTestOnBorrow(testOnBorrow); datasource.setTestOnReturn(testOnReturn); datasource.setPoolPreparedStatements(poolPreparedStatements); datasource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize); try { datasource.setFilters(filters); } catch (SQLException e) { e.printStackTrace(); } datasource.setConnectionProperties(connectionProperties); AtomikosDataSourceBean atomikosDataSourceBean=new AtomikosDataSourceBean(); atomikosDataSourceBean.setUniqueResourceName(dbName); //atomikosDataSourceBean.setUniqueResourceName(dbUrl.substring(32 dbUrl.length()-76)); atomikosDataSourceBean.setXaDataSource(datasource); return atomikosDataSourceBean; } }

3、构建一个service处理事务性操作主类,配置@Transactional支持事务

@Service @Transactional(transactionManager = "jtaManger" rollbackFor = Exception.class) public class RefillDataCenterServiceImpl implements RefillDataCenterService { /** * 账号金额service组件 */ @Autowired private AccountAmountService accountAmountService; /** * 充值订单service组件 */ @Autowired private RefillOrderService refillOrderService; /** * 抽奖机会service组件 */ @Autowired private LotteryDrawService lotteryDrawService; @Override public void finishRefillData(RefillRequest refillRequest) { // 完成支付转账 accountAmountService.transfer(refillRequest.getUserAccountId() refillRequest.getBusinessAccountId() refillRequest.getPayAmount()); // 创建充值订单 refillOrderService.add(createRefillOrder(refillRequest)); // 给用户增加一次抽奖机会 lotteryDrawService.increment(refillRequest.getUserAccountId()); //。。。。。。。。。。。中间代码业务不展示 } }

4、上面的finishRefillData方法在操作多个数据源时,此类会被代理,然后控制由jtaManger事务管理器来统一管理事务。

一文看懂分布式事务(又问分布式事务)(2)

简单点理解看下图:

一文看懂分布式事务(又问分布式事务)(3)

2、最终一致性分布式事务方案

由于篇幅有点长,大家先理解单体下的多数据源的分布式事务,我们下节讲解最终一致性分布式事务,如:本地消息表、MQ 可靠消息最终一至事务、最大努力通知、补偿事务 TCC、saga事务、阿里的Seata等。

猜您喜欢: