Springboot+nacos+seata实现简单的分布式事务

上一篇文章把三个服务都注册进nacos中了,这次就开始写业务代码

首先先创建三个数据库,每个数据库都需要有一张记录表,一张回滚表

order表

CREATE TABLE `t_order` (`id` bigint NOT NULL AUTO_INCREMENT,`user_id` bigint DEFAULT NULL ,`product_id` bigint DEFAULT NULL ,`count` int DEFAULT NULL ,`money` decimal(11,0) DEFAULT NULL ,`status` int DEFAULT NULL ,PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=32 DEFAULT CHARSET=utf8;CREATE TABLE `undo_log` (`branch_id` bigint NOT NULL COMMENT 'branch transaction id',`xid` varchar(128) NOT NULL COMMENT 'global transaction id',`context` varchar(128) NOT NULL COMMENT 'undo_log context,such as serialization',`rollback_info` longblob NOT NULL COMMENT 'rollback info',`log_status` int NOT NULL COMMENT '0:normal status,1:defense status',`log_created` datetime(6) NOT NULL COMMENT 'create datetime',`log_modified` datetime(6) NOT NULL COMMENT 'modify datetime',UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ;

storage表

CREATE TABLE `t_storage` (`id` bigint NOT NULL AUTO_INCREMENT,`product_id` bigint DEFAULT NULL,`total` int DEFAULT NULL,`used` int DEFAULT NULL,`residue` int DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;--在表中插入一条数据
INSERT INTO `t_storage` VALUES ('1', '1', '100', '0', '100');CREATE TABLE `undo_log` (`branch_id` bigint NOT NULL COMMENT 'branch transaction id',`xid` varchar(128) NOT NULL COMMENT 'global transaction id',`context` varchar(128) NOT NULL COMMENT 'undo_log context,such as serialization',`rollback_info` longblob NOT NULL COMMENT 'rollback info',`log_status` int NOT NULL COMMENT '0:normal status,1:defense status',`log_created` datetime(6) NOT NULL COMMENT 'create datetime',`log_modified` datetime(6) NOT NULL COMMENT 'modify datetime',UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='AT transaction mode undo table';

account表

CREATE TABLE `t_account` (`id` bigint NOT NULL AUTO_INCREMENT,`user_id` bigint DEFAULT NULL,`total` decimal(10,0) DEFAULT NULL,`used` decimal(10,0) DEFAULT NULL,`residue` decimal(10,0) DEFAULT '0',PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;--插入一条数据
INSERT INTO `t_account` VALUES ('1', '1', '1000', '0', '1000');CREATE TABLE `undo_log` (`branch_id` bigint NOT NULL COMMENT 'branch transaction id',`xid` varchar(128) NOT NULL COMMENT 'global transaction id',`context` varchar(128) NOT NULL COMMENT 'undo_log context,such as serialization',`rollback_info` longblob NOT NULL COMMENT 'rollback info',`log_status` int NOT NULL COMMENT '0:normal status,1:defense status',`log_created` datetime(6) NOT NULL COMMENT 'create datetime',`log_modified` datetime(6) NOT NULL COMMENT 'modify datetime',UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

到此,三个数据库六张表建好了下面写代码

order服务

新建order实体

public class Order {private int id;private int userId;private int productId;private int count;private int money;private int status;
}//我这自己创建了get,set方法

OrderMapper类,用于操作数据库

@Mapper
public interface OrderMapper {@Insert("insert into t_order(user_id,product_id,count,money,status) values(#{userId},#{productId},#{count},#{money},#{status})")int create(Order order);@Update("update t_order set status = #{status} where user_id = 1;")void update(int status);}

StorageService接口用于使用openfeign调用另一个服务

//@FeignClient:将远程服务xxx映射为一个本地Java方法调用
@FeignClient(name = "seataStorage")
public interface StorageService {@PostMapping(value = "/storage/decrease")int decrease(@RequestParam("count") Object count,@RequestParam("XID") String XID);
}/**
*count参数是自己定义的用于模拟发生条件不成立而回滚,XID就是TC 针对这个全局事务生成一个全局唯一的 XID
*XID参数必须传,如果不传的话Storage服务不会回滚
*/

AccountService接口用于使用openfeign调用另一个服务

@FeignClient(name = "seataAccount")
public interface AccountService {@PostMapping(value = "/account/decrease")int decrease(@RequestParam("money") Object money , @RequestParam("XID") String XID);
}

OrderService接口及其实现类

public interface OrderService {int create(Order order);
}@Service
public class OrderImpl implements OrderService {@AutowiredOrderMapper orderMapper;@ResourceAccountService accountService;@ResourceStorageService storageService;@Override//这个注解表示是一个分布式事务,在这个注解包括的代码块中,不管事本服务的sql还是feign调用的服务的sql都会被seata增强@GlobalTransactional(name = "service.vgroupMapping.mytest", rollbackFor = Exception.class)public int create(Order order) {order.setUserId(1);order.setStatus(0);orderMapper.create(order);System.out.println(RootContext.getXID());storageService.decrease(order.getCount(),RootContext.getXID());accountService.decrease(order.getMoney(),RootContext.getXID());orderMapper.update(0);return 1;}
}

OrderController类用于接口调用

@RestController
public class OrderController {@AutowiredOrderService orderService;@PostMapping("/test")public void create(int count , int money) {Order order = new Order();order.setProductId(100);order.setCount(count);order.setMoney(money);orderService.create(order);}
}

启动类

@SpringBootApplication
//让注册中心能够发现,扫描到该服务
@EnableDiscoveryClient
//告诉框架扫描所有使用注解@FeignClient定义的feign客户端
@EnableFeignClients(basePackages = "com.example.springdemoOrder")
public class Springdemo1Application {public static void main(String[] args) {SpringApplication.run(Springdemo1Application.class, args);}
}
Storage服务

新建order实体

public class Storage {private int id;private int productId;private int total;private int used;private int residue;//自己建get,set方法
}

StorageMapper接口

@Mapper
public interface StorageMapper {@Results(id = "storage" , value = {@Result(property = "id" , column = "id" , id = true),@Result(property = "productId" , column = "product_id"),@Result(property = "total" , column = "total"),@Result(property = "used" , column = "used"),@Result(property = "residue" , column = "residue")})@Select("select * from t_storage where id = #{id}")Storage selectByProductId(int id);@Update("update t_storage set total = #{total},used = #{used} , residue = #{residue} where id = #{id}")int update(Storage record);
}

StorageService接口及其实现类

public interface StorageService {int decrease(Object count);
}@Service
public class StorageServiceImpl implements StorageService {@AutowiredStorageMapper storageMapper;@Override@Transactionalpublic int decrease(Object count) {Storage storage = storageMapper.selectByProductId(1);int co = (int) count;if (storage != null && storage.getResidue().intValue() >= co) {Storage storage2 = new Storage();storage2.setId(1);storage.setUsed(storage.getUsed() + co);storage.setResidue(storage.getTotal().intValue() - storage.getUsed());int decrease = storageMapper.update(storage);System.out.println("成功");return decrease;} else {System.out.println("开始回滚!");throw new RuntimeException("失败!");}}
}

StorageController类

@RestController
@RequestMapping("/storage")
public class StorageController {@AutowiredStorageService storageService;@PostMapping("/decrease")public int  test(@RequestParam("count") String count, @RequestParam("XID") String XID){int num = Integer.valueOf(count);RootContext.bind(XID);System.out.println(RootContext.getXID());int decrease = storageService.decrease(num);int result;if (decrease > 0) {result = 1;} else {result = 0;}return result;}
}
Account服务

Account实体

public class Account {private int id;private int userId;private int total;private int used;private int residue;
}

AccountMapper接口

@Mapper
public interface AccountMapper {@Results(id = "acount",value = {@Result(property = "id",column = "id",id = true),@Result(property = "userId",column = "user_id"),@Result(property = "total",column = "total"),@Result(property = "used",column = "used"),@Result(property = "residue",column = "residue")})@Select("select * from t_account where id = 1")Account selectByUserId();@Update("update t_account set used = #{used} , residue = #{residue} where id = 1")int decrease(Account account);}

ACcountService接口及其实现类

public interface AccountService {int decrease(Object money);
}@Service
public class AccountServiceImpl implements AccountService {@AutowiredAccountMapper accountDao;@Override@Transactionalpublic int decrease(Object money) {Account account = accountDao.selectByUserId();int used = account.getUsed();int residue = account.getResidue();int mo = (int) money;//如果传过来的参数小于数据库的数据就回滚if (mo<residue){account.setUsed(used+mo);account.setResidue(residue-mo);accountDao.decrease(account);}else {throw new RuntimeException("错误");}return 1;}
}

AccountController类

@RestController
@RequestMapping("/account")
public class AccountController {@AutowiredAccountService account;@PostMapping("/decrease")public int test(@RequestParam("money") String money ,@RequestParam("XID") String XID){RootContext.bind(XID);System.out.println(RootContext.getXID());int m = Integer.valueOf(money);int decrease = account.decrease(m);int result;if (decrease==1){result = 1;}else {result = 0;}return result;}
}

接下来启动三个服务试试,然后调用接口试试正常的情况

storage表

account表

接下来我们模拟回滚
参数:

然后发现主服务抛出错误

但是我们也没法知道到底发没发生回滚啊,去idea打个断点试试,因为我们是模拟的account服务抛出错误,所以在主服务的OrderImpl打个断点试试

进入断点

Order表已经插入数据了

Order表的回滚表

Storage表也修改了数据

Storage表的回滚表


断点去了之后,因为account服务抛出错误,所以开始回滚

Order表

Storage表

到这里就结束了,代码地址https://github.com/Melons-skin/seata-nacos-springboot-

Springboot+nacos+seata实现简单分布式事务经验分享:二相关推荐

  1. SpringBoot+Nacos+Seata实现Dubbo分布式事务管理

    SpringBoot+Nacos+Seata实现Dubbo分布式事务管理 https://www.shangmayuan.com/a/a3ba056126ba45db9b8dfd5b.html 源码下 ...

  2. SpringBoot+Zookeeper+Seata实现Dubbo分布式事务管理

    面我已经写过一篇SpringBoot+Nacos+Seata实现Dubbo分布式事务管理的文章,今天为什么还要写这篇呢,是因为好多公司还在用Zookeeper作为Dubbo的注册中心和配置中心在大规模 ...

  3. druid seata 配置_分布式事务解决方案——Seata使用

    在微服务开发过程中分布式事务一直是一个比较重要的问题,之前对于分布式事务的解决方法一般会通过MQ的最终一致性来解决,尤其是RocketMQ的事务消息,感兴趣的可以看Spring Boot整合Rocke ...

  4. Spring Cloud Alibaba 高级特性 分布式事务:Alibaba Seata 如何实现分布式事务

    本讲咱们要解决分布式事务这一技术难题,这一讲咱们将介绍三方面内容: 讲解分布式事务的解决方案: 介绍 Alibaba Seata 分布式事务中间件: 分析 Seata 的 AT 模式实现原理. 分布式 ...

  5. SpringCloud分布式事务,版本二:添加 Seata 分布式事务版本

    基于 Seata 1.4.0 版本 首先贴出此项目地址:Seata 分布式事务版本 先了未添加事务项目再看此版本:未添加事务版本 此文章是基于上一篇的项目基础上添加的内容,所以务必先看上一篇 Seat ...

  6. 老板,明年我用Seata搞定分布式事务管理的规范化建设 | 中篇

    辞旧迎新,22年要结束了,明年做什么想好了嘛?要不要用 Seata 搞定公司分布式事务管理的规范化建设? 欢迎关注微信公众号「架构染色」交流和学习 一.背景 在上一篇<明年用Seata搞定分布式 ...

  7. 分布式事务:Alibaba Seata 如何实现分布式事务

    * 讲解分布式事务的解决方案 * 介绍Alibaba Seata 分布式事务中间件 * 分析Seata 的AT 模式实现原理 分布式架构中两种经典的分布式事务解决方案: 二阶段提交.三阶段提交 二阶段 ...

  8. 事务 | Spring Cloud 分布式事务管理(二)2pc/3pc

    Spring Cloud 分布式事务管理(二)2pc/3pc 上一篇 Spring Cloud 分布式事务管理 上一章,讲到了微服务带来的优点和缺点以及分布式事务的不确定性.这节说一下2pc/3pc ...

  9. [软考]系统架构设计师 备考经验分享(二) - 知识点学习+综合知识篇

    2021.12.20 更新下成绩 49,53,55 原文: 本篇对应备考计划中的1.2阶段: 相关分享: 备考计划篇:[软考]系统架构设计师 备考经验分享(一) - 备考计划篇 知识点学习+综合知识篇 ...

最新文章

  1. github 项目绑定自己的域名
  2. java将一个数字转换为数组_Java 数组
  3. 怎么通过media foundation将图像数据写入虚拟摄像头_不知道怎么挑手机?性价比神机绝对适合你...
  4. 实现单链表--Python
  5. TPL Dataflow组件应对高并发,低延迟要求
  6. 使用adb命令获取手机ip地址
  7. 用html5制作古诗,古诗词书签制作
  8. 迅雷离线下载分享网站
  9. Android组件化开发实践和案例分享 | 融合数10个项目模块
  10. python安装requirement.txt的扩展包
  11. Python中os.sep的用法
  12. pandas操作大全
  13. LINQ之Update
  14. .NET使用MailKit进行邮件处理
  15. ACM概率期望dp刷题总结
  16. js/Jquery通过MutationObserver实现监听dom元素的属性变化 用div简单实例
  17. ICV光子盒:2023全球量子通信与安全产业发展展望
  18. Windows server 2008 DNS服务器架构(八)
  19. 【转载】听说树莓派性能差,什么最好别尝试?
  20. [展览人周刊]华展云20170710期

热门文章

  1. 用Zoundry离线更新Bloger
  2. python整形变量赋初值_为了给整型变量x、y、z赋初值10,下面 Python赋值语句正确的是_学小易找答案...
  3. K9F1208U0M(64M nand flash)手册阅读以及相关驱动程序分析
  4. 2022年上半年软考(中/高级)考试报名向导
  5. WDM模式驱动简单例子
  6. BurpSuite安装插件教程:BurpCrypto: 万能网站密码爆破测试工具
  7. 安卓原生系统_全新国产操作系统登场:原生支持微信、吃鸡等海量安卓App
  8. 逗号表达式 java_逗号表达式的用法
  9. c语言常量与变量ppt,C语言 变量、常量与数据类型.ppt
  10. python实现循环赛日程表问题的算法_循环赛日程表的分治算法实现实验报告gxl.doc...