前言
-
什么是分布式事务
在业务系统中,如果发起了一个rpc请求(远程调用请求)访问了其他的服务。
那么该服务的事务我们调用方是无法控制的,比如回滚或者提交。
所以这就涉及到数据到一致性问题。
就如同下面这种情况
此次业务调用中,发起者是Business,如果调用到rpc服务中,三有一是出现异常到情况,那么就需要统一回滚,就算之前有某个调用成功到服务,也需要回滚。
事务要么一起成功,要么一起失败,所以数据才可以一致。 -
seate怎么实现分布式事务
seate实现分布式事务的方法如下图
其实就是维护”一个大的事务“,子事务成功,才可以全部提交。
开始
模拟场景
项目地址
参考里面的springboot
1. 安装一个mysql(我使用的是5.7)
2.初始化一个数据库用这sql文件 [sql/init_db.sql](https://github.com/seata/seata-samples/blob/master/springboot/src/main/resources/sql/initial_db.sql)
3. 修改yml的配置,设置mysql的用户名和密码(https://github.com/seata/seata-samples/blob/master/springboot/src/main/resources/application.yml#L13-L35)
4. 设置dubbo的注册中心 `zookeeper://localhost:2181`
5.启动 seata server
6. 启动 SeataSpringbootApp .
7. 访问 http://127.0.0.1:9999/demo//asset/assign , 观察事务的一致性
说明:
1.zookeeper我使用的是zookeeper:3.5.5
2.seata server地址,启动seata/server/src/main/java/io/seata/server/Server.java
代码
SeataSpringbootApp主要逻辑
这是我们访问的接口
@RequestMapping(value = "/asset/assign")
@ResponseBody
public String assetAssign() {
LOGGER.info("welcome to deposit");
String result;
try {
AssetAssign assetAssign = assignService.increaseAmount(
ASSET_ID);
result = assetAssign.toString();
} catch (Exception e) {
result = ExceptionUtils.getMessage(e);
}
return result;
}
主要的业务方法是这个increaseAmount
@Override
@Transactional
@GlobalTransactional
public AssetAssign increaseAmount(String id) {
LOGGER.info("Assign Service Begin ... xid: " + RootContext.getXID() + "\n");
//增加资产
AssetAssign assetAssign = assignRepository.findById(id).get();
assetAssign.setStatus("2");
assignRepository.save(assetAssign);
// 调用rpc服务增加资产
assetService.increase();
return assetAssign;
}
这里主要是assetService.increase,这个rpc。
@Override
public int increase() {
LOGGER.info("Asset Service Begin ... xid: " + RootContext.getXID() + "\n");
Asset asset = assetRepository.findById(ASSET_ID).get();
asset.setAmount(asset.getAmount().add(new BigDecimal("1")));
assetRepository.save(asset);
//如果上面调用方没有GlobalTransactional注解的话,那么就会出现下面的情况
//这里是远程的方法,抛出异常,数据已经插入到数据库里面了
throw new RuntimeException("test exception for seata, your transaction should be rollbacked,asset=" + asset);
}
加了GlobalTransactional注解,那么调用到远程rpc,后面远程抛出RuntimeException,那么事务会回滚,实现了我们的目的。