微前端架构如何改变企业的开发模式与效率提升
720
2023-03-03
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
httpsYVjoDJo://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
]
http:// },
{
"@class": "io.seata.rm.datasource.sql.struct.Field",
"name": "residue",
"keyType": "NULL",
"type": 3,
"value": [
"java.math.BigDecimal",
300
]
}
]
]
}
]
]
}
}
]
]
}
可以看到里面有beforeimage和afterimage快照记录,通过这些记录可以实现逆操作,重新写进数据实现回滚。
本文只是简单的配置,后续会进行详细补充。
所有的代码都在GitHub
https://github.com/MaTsukun/springcloud2020
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~