您好,登录后才能下订单哦!
Springcloud中的分布式事务怎么利用seata实现?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。
Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。
大致上seata分为TC,TM,RM三大构建成整体。它们之间的包含关系如下。即一(xid主键编码,记录信息)带三(TC,TM,RM)
下面之间构建项目进行测试。
1.下载seata并解压,然后改动配置文件。
http://seata.io/zh-cn/blog/download.html官网下载。
解压之后到conf中修改file和registry文件,修改之前一定记得先备份。
file.conf,改动两个地方
将group后面的参数定义一个名字,随意
存储方式选db放在数据库,自然其配置信息根据自己的数据库去填写。
然后是register文件,填写信息将seata注册到nacos中。
启动自然是在bin中打开bat文件即可,注意需要先启动naco。
2.构建项目(order,storage,account)
演示整体的服务调用还有服务报错的时候进入回滚。通过创建订单->检查库存并扣除->检查账户并扣除->修改订单状态
具体代码可查看GitHub
https://github.com/MaTsukun/springcloud2020
关键的service方法
@Service @Slf4j public class OrderServiceImpl implements OrderService{ @Resource private OrderMapper orderMapper; @Resource private StorageService storageService; @Resource private AccountService accountService; @Override @GlobalTransactional(name="abc-create-order",rollbackFor = Exception.class) public void create(Order order){ //1.创建订单 log.info("开始创建订单"); orderMapper.create(order); //2.减少库存 log.info("查询库存并且进行更改"); storageService.decrease(order.getProductId(),order.getCount()); //3.扣除费用 log.info("查询余额并扣除费用"); accountService.updateAccount(order.getUserId(),order.getMoney()); //4.修改状态 log.info("更改订单状态"); orderMapper.update(order.getUserId(),0); log.info("订单结束,O(∩_∩)O哈哈~"); } }
可以看到在order项目中同时调用了storage和account的项目的方法,采用的是openfeign,整体形成了一个链路,成为一个整的事务。
而添加的GlobalTransactional注解则保证了事务中任何一方出现错误就会使整个项目的执行过程进行回滚,而不是单事务的回滚。
3.seata回滚原理
在每次注解的方法里进行执行sql语句的时候都会创建一个id记录此次的写操作同时在每次的写操作前后都会生成前置记录和后置记录,可以在出现错误回滚的时候,通过记录进行逆操作回滚重新将数据写回去。
通过数据库配置的seata库展示可以看见对应的记录id信息,通过debug模式暂停服务,查看记录的信息。
global的全局xid
account表的undo记录
记录的信息json格式
{ "@class": "io.seata.rm.datasource.undo.BranchUndoLog", "xid": "192.168.2.141:8091:2060193863", "branchId": 2060193875, "sqlUndoLogs": [ "java.util.ArrayList", [ { "@class": "io.seata.rm.datasource.undo.SQLUndoLog", "sqlType": "UPDATE", "tableName": "t_account", "beforeImage": { "@class": "io.seata.rm.datasource.sql.struct.TableRecords", "tableName": "t_account", "rows": [ "java.util.ArrayList", [ { "@class": "io.seata.rm.datasource.sql.struct.Row", "fields": [ "java.util.ArrayList", [ { "@class": "io.seata.rm.datasource.sql.struct.Field", "name": "id", "keyType": "PrimaryKey", "type": -5, "value": [ "java.lang.Long", 1 ] }, { "@class": "io.seata.rm.datasource.sql.struct.Field", "name": "used", "keyType": "NULL", "type": 3, "value": [ "java.math.BigDecimal", 600 ] }, { "@class": "io.seata.rm.datasource.sql.struct.Field", "name": "residue", "keyType": "NULL", "type": 3, "value": [ "java.math.BigDecimal", 400 ] } ] ] } ] ] }, "afterImage": { "@class": "io.seata.rm.datasource.sql.struct.TableRecords", "tableName": "t_account", "rows": [ "java.util.ArrayList", [ { "@class": "io.seata.rm.datasource.sql.struct.Row", "fields": [ "java.util.ArrayList", [ { "@class": "io.seata.rm.datasource.sql.struct.Field", "name": "id", "keyType": "PrimaryKey", "type": -5, "value": [ "java.lang.Long", 1 ] }, { "@class": "io.seata.rm.datasource.sql.struct.Field", "name": "used", "keyType": "NULL", "type": 3, "value": [ "java.math.BigDecimal", 700 ] }, { "@class": "io.seata.rm.datasource.sql.struct.Field", "name": "residue", "keyType": "NULL", "type": 3, "value": [ "java.math.BigDecimal", 300 ] } ] ] } ] ] } } ] ] }
可以看到里面有beforeimage和afterimage快照记录,通过这些记录可以实现逆操作,重新写进数据实现回滚。
看完上述内容,你们掌握Springcloud中的分布式事务怎么利用seata实现的方法了吗?如果还想学到更多技能或想了解更多相关内容,欢迎关注亿速云行业资讯频道,感谢各位的阅读!
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。