文章知识来源主要来源于:赵俊夫先生的博客 以下为原文链接
https://blog.csdn.net/u011177064/category_9572944.html
本章介绍
主要为了测试 Seata AT模式 应对正常 正常 正常 并发的正常处理
1:测试:调用服务 添加@Transactional 或者 去除事务 同时 被调用服务 不添加事务
由于调用服务不管
添加事务@Transactional(rollbackFor = RuntimeException.class)
还是不加事务
该事务的作用域 只是当前服务的当前接口 不影响其他服务
同时provider服务 也是的就是执行 order_tbl的逻辑 没有添加事务
因此provider服务 的逻辑报错也不会影响
2:测试:调用服务 添加@GlobalTransactional 被调用服务 不添加事务
可以看到数据完全没有改变
同时调用服务 根据XID 回滚的相关日志
3:测试:调用服务 添加@GlobalTransactional 同时 被调用服务添加@Transactional
可以看到数据完全没有改变
同时发现被调用服务 的 XID
在被调用服务开启了Transactional事务后还是保持不变
4:测试:调用服务 被调用服务 同时 添加@GlobalTransactional
可以看到数据完全没有改变
同时发现被调用服务 的 XID
在被调用服务开启了@GlobalTransactional事务后还是保持不变
5:测试:把provider 服务 抛异常的代码去除
可以看到数据都正常了
同时order表的主键ID从1直接变成5了
说明之前插入后又回滚了
6:一个简单的结论
seata 的 AT模式
在调用端添加@GlobalTransactional注解后
后续的被调用端
1:不添加任何事务
2:添加@Transactional 事务
3:添加@GlobalTransactional 事务
都不会再影响 分布式事务
所有我们应该把所有的增删 和 修改操作都添加 分布式事务吗?
需要注意seata 的 AT模式 的 分布式事务 是需要给数据库加锁的
对性能还是有损耗的。
因此建议如果确认该接口的后续调用不会影响调用到其他服务的增删 和 修改操作
建议添加@Transactional 事务即可
8:新增一个测试接口purchaseFirst(查看undo_log)
@Override
@GlobalTransactional(rollbackFor = RuntimeException.class)
public void purchaseFirst(String userId, String commodityCode, Integer orderCount) {
//为了与日志区分 使用 System打印日志
System.out.println("我先进行调用 进入purchase 购买下单,模拟全局事务提交 请求");
System.out.println("我先进行调用 order XID " + RootContext.getXID());
//storageService服务 db_storage库 storage_tbl表
storageFeignClientService.seatadeductStorage(commodityCode, orderCount);
//休眠60秒,期间去调用其他接口
try {
Thread.sleep(1000*60);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("我先进行调用 休眠60秒,期间去调用其他接口");
//providerService服务 db_order库 order_tbl表
providerFeignClientService.seataCreateOrder(userId, commodityCode, orderCount);
}
初始值
Storage表的 count 为998
Order表有2条数据
原接口入参 userId 1001 新接口入参 userId 1002
测试流程:请求新接口
产生结果:
Storage表的 count 为997
Order表新增一条数据 userId 1002
注意:在请求期间 storage的undo_log 表会出现数据
其XID 正是请求ID :126860430807142400
[图片上传失败...(image-1a9a88-1618753104257)]
9:进行并发测试 @GlobalTransactional
并发测试1:
初始值
Storage表的 count 为997
Order表有三条数据
测试流程:请求新接口 5秒后请求原有接口
先清空idea的日志
进行两次测试(每次都把数据还原从成初始数据,注意修改Order的主键ID起始值)
两次测试结果都为
Storage表的 count 为995
Order表新增两条数据 userId 1001 userId 1002
最终结果完全正常
期间 有可能undo_log 有一个(正常)
期间 有可能undo_log 有两个(不正常)(不知道为什么 同样的XID进入了两次)
并发测试2:
初始值
Storage表的 count 为995
Order表有5条数据
测试流程:请求新接口 5秒后请求原有接口
先清空idea的日志
测试结果为
Storage表的 count 为993
Order表新增两条数据 userId 1001 userId 1002
期间 有可能undo_log 有一个(正常)
并发测试3:
初始值
Storage表的 count 为993
Order表有7条数据
测试流程:请求新接口 5秒后请求原有接口 5秒后请求原有接口
先清空idea的日志
测试结果为
Storage表的 count 为990
Order表新增三条数据 userId 1001 userId 1001 userId 1002
[图片上传失败...(image-968199-1618753337730)]
期间 有可能undo_log 有一个(正常)
@GlobalTransactional并发测试结论:
@GlobalTransactional完成解决并发的请求
1:不管有多个并发的请求进来都能实现最终一致性
2:同一个请求在请求期间 不管是 生成一条undo_log 还是两条undo_log
最终都数据都最终一致(由于Feign重复请求 后续会提及)
项目连接
请配合项目代码食用效果更佳:
项目地址:
https://github.com/hesuijin/spring-cloud-alibaba-project
Git下载地址:
https://github.com.cnpmjs.org/hesuijin/spring-cloud-alibaba-project.git
https://github.com/hesuijin/spring-cloud-alibaba-project
Git下载地址:
https://github.com.cnpmjs.org/hesuijin/spring-cloud-alibaba-project.git
在service-storage-demo 模块下
在service-consumer-demo 模块下
在service-provider-demo 模块下
在service-provider-demo-other 模块下
网友评论