个人随笔
目录
二十一、springCloudAlibaba-seata测试环境准备
2023-11-08 21:26:06

二十、springCloudAlibaba-seata环境搭建TC(Server端)我们已经搭建好了seata的环境,那么我们这里来搭建一下项目的环境

一、案例

我们打算搭建两个服务,一个订单服务,一个库存服务,分别有自己的数据库,订单服务通过feign调用库存服务。伪代码如下

  1. @Transactional
  2. public String add(Long merchId) {
  3. System.out.println("新增订单开始"+merchId);
  4. Order order = new Order();
  5. order.setOrderNo(1l);
  6. order.setOrderName("新增订单,对应商品"+merchId);
  7. orderMapper.insert(order);
  8. System.out.println("新增订单结束"+merchId);
  9. //这里是远程调用库存服务扣减库存
  10. stockService.reduce(1l);
  11. System.out.println("扣减库存结束"+merchId);
  12. //这里报错
  13. int i =1/0;
  14. return null;
  15. }

上面开始是在订单数据库插入一条订单数据,然后用feign调用远程库存服务扣减库存,扣减库存完后再执行一个i=1/0;方法触发异常导致该事务回滚,由于没有解决分布式事务的问题,结果应该是订单表没有数据,而库存却扣减成功。下面我们来搭建一下。

二、环境搭建准备

1、参考

五分钟搭建springboot2.7.16+druid+mybatis-plus环境
三、springCloudAlibaba-feign的简单使用

2、订单数据库

  1. CREATE DATABASE order_seata;
  2. CREATE TABLE tb_order(
  3. order_no BIGINT not null primary key COMMENT '主键ID',
  4. order_name VARCHAR(64) COMMENT '订单名字'
  5. );

3、库存数据库

  1. CREATE DATABASE stock_seata;
  2. CREATE TABLE tb_stock(
  3. merch_id BIGINT not null primary key COMMENT '主键ID',
  4. count BIGINT COMMENT '库存'
  5. );
  6. INSERT INTO `tb_stock` (`merch_id`, `count`) VALUES (1, 100);

三、订单服务代码

1、依赖pom.xml

  1. <dependency>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter-web</artifactId>
  4. </dependency>
  5. <!--服务注册与发现 -->
  6. <dependency>
  7. <groupId>com.alibaba.cloud</groupId>
  8. <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
  9. </dependency>
  10. <dependency>
  11. <groupId>org.springframework.cloud</groupId>
  12. <artifactId>spring-cloud-starter-openfeign</artifactId>
  13. </dependency>
  14. <!--数据库配置-->
  15. <dependency>
  16. <groupId>mysql</groupId>
  17. <artifactId>mysql-connector-java</artifactId>
  18. <version>8.0.25</version>
  19. </dependency>
  20. <!--数据源-->
  21. <dependency>
  22. <groupId>com.alibaba</groupId>
  23. <artifactId>druid</artifactId>
  24. <version>1.1.22</version>
  25. </dependency>
  26. <!--自动化配置-->
  27. <dependency>
  28. <groupId>com.alibaba</groupId>
  29. <artifactId>druid-spring-boot-starter</artifactId>
  30. <version>1.1.22</version>
  31. </dependency>
  32. <!--mybatis-plus -->
  33. <dependency>
  34. <groupId>com.baomidou</groupId>
  35. <artifactId>mybatis-plus-boot-starter</artifactId>
  36. <version>3.4.2</version>
  37. </dependency>

2、OrderController

  1. @RestController
  2. @RequestMapping("/order")
  3. public class OrderController {
  4. @Autowired
  5. OrderService orderService;
  6. @RequestMapping("/add")
  7. public String add(){
  8. String msg = orderService.add(1l);
  9. return "新增订单成功"+msg;
  10. }
  11. }

3、OrderMapper

  1. @Repository
  2. public interface OrderMapper extends BaseMapper<Order> {
  3. }

4、StockService

  1. @FeignClient(name="stock-service",path="/stock")
  2. public interface StockService {
  3. @RequestMapping("/reduce")
  4. public String reduce(@RequestParam("merchId")Long merchId);
  5. }

5、Order

  1. @TableName("tb_order")
  2. public class Order {
  3. @TableField("order_no")
  4. private Long orderNo;
  5. @TableField("order_name")
  6. private String orderName;
  7. public Long getOrderNo() {
  8. return orderNo;
  9. }
  10. public void setOrderNo(Long orderNo) {
  11. this.orderNo = orderNo;
  12. }
  13. public String getOrderName() {
  14. return orderName;
  15. }
  16. public void setOrderName(String orderName) {
  17. this.orderName = orderName;
  18. }
  19. @Override
  20. public String toString() {
  21. return "Order{" +
  22. "orderNo=" + orderNo +
  23. ", orderName='" + orderName + '\'' +
  24. '}';
  25. }
  26. }

6、OrderService

  1. public interface OrderService {
  2. public String add(Long merchId);
  3. }

7、OrderServiceImpl

  1. @Service
  2. public class OrderServiceImpl implements OrderService {
  3. @Autowired
  4. StockService stockService;
  5. @Autowired
  6. OrderMapper orderMapper;
  7. @Transactional
  8. @Override
  9. public String add(Long merchId) {
  10. System.out.println("新增订单开始"+merchId);
  11. Order order = new Order();
  12. order.setOrderNo(1l);
  13. order.setOrderName("新增订单,对应商品"+merchId);
  14. orderMapper.insert(order);
  15. System.out.println("新增订单结束"+merchId);
  16. //新增订单
  17. stockService.reduce(1l);
  18. System.out.println("扣减库存结束"+merchId);
  19. int i =1/0;
  20. return null;
  21. }
  22. }

8、OrderNacosFeignSeataApplication

  1. @SpringBootApplication
  2. @MapperScan("com.suibibk.springCloud.order.mapper")
  3. @EnableFeignClients
  4. public class OrderNacosFeignSeataApplication {
  5. public static void main( String[] args ) {
  6. SpringApplication.run(OrderNacosFeignSeataApplication.class,args);
  7. }
  8. }

9、application.yml

  1. server:
  2. port: 8013
  3. spring:
  4. application:
  5. name: order-nacos-feign-seata
  6. cloud:
  7. nacos:
  8. server-addr: 127.0.0.1:8848
  9. discovery:
  10. username: nacos
  11. password: nacos
  12. namespace: public
  13. datasource:
  14. driver-class-name: com.mysql.cj.jdbc.Driver
  15. url: jdbc:mysql://192.168.192.19:3309/order_seata?serverTimezone=Asia/Shanghai
  16. username: root
  17. password: 123456
  18. type: com.alibaba.druid.pool.DruidDataSource #Druid类型

四、库存服务代码


库存服务暂时不调用别的服务,所以不引入feign

1、引入依赖pom.xml

  1. <dependency>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter-web</artifactId>
  4. </dependency>
  5. <!--服务注册与发现 -->
  6. <dependency>
  7. <groupId>com.alibaba.cloud</groupId>
  8. <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
  9. </dependency>
  10. <!--数据库配置-->
  11. <dependency>
  12. <groupId>mysql</groupId>
  13. <artifactId>mysql-connector-java</artifactId>
  14. <version>8.0.25</version>
  15. </dependency>
  16. <!--数据源-->
  17. <dependency>
  18. <groupId>com.alibaba</groupId>
  19. <artifactId>druid</artifactId>
  20. <version>1.1.22</version>
  21. </dependency>
  22. <!--自动化配置-->
  23. <dependency>
  24. <groupId>com.alibaba</groupId>
  25. <artifactId>druid-spring-boot-starter</artifactId>
  26. <version>1.1.22</version>
  27. </dependency>
  28. <!--mybatis-plus -->
  29. <dependency>
  30. <groupId>com.baomidou</groupId>
  31. <artifactId>mybatis-plus-boot-starter</artifactId>
  32. <version>3.4.2</version>
  33. </dependency>

2、StockController

  1. @RestController
  2. @RequestMapping("/stock")
  3. public class StockController {
  4. @Autowired
  5. StockService stockService;
  6. @RequestMapping("/reduce")
  7. public String reduce(Long merchId){
  8. stockService.reduce(merchId);
  9. return "库存扣减成功";
  10. }
  11. }

3、StockMapper

  1. @Repository
  2. public interface StockMapper extends BaseMapper<Stock> {
  3. }

4、Stock

  1. @TableName("tb_stock")
  2. public class Stock {
  3. @TableField("merch_id")
  4. private Long merchId;
  5. @TableField("count")
  6. private Long count;
  7. public Long getMerchId() {
  8. return merchId;
  9. }
  10. public void setMerchId(Long merchId) {
  11. this.merchId = merchId;
  12. }
  13. public Long getCount() {
  14. return count;
  15. }
  16. public void setCount(Long count) {
  17. this.count = count;
  18. }
  19. @Override
  20. public String toString() {
  21. return "Stock{" +
  22. "merchId=" + merchId +
  23. ", count=" + count +
  24. '}';
  25. }
  26. }

5、StockService

  1. public interface StockService {
  2. void reduce(Long merchId);
  3. }

6、StockServiceImpl

  1. @Service
  2. public class StockServiceImpl implements StockService {
  3. @Autowired
  4. StockMapper stockMapper;
  5. @Transactional
  6. @Override
  7. public void reduce(Long merchId) {
  8. System.out.println("扣减库存开始"+merchId);
  9. QueryWrapper<Stock> queryWrapper = new QueryWrapper<Stock>();
  10. queryWrapper.eq("merch_id",1l);
  11. Stock stock= stockMapper.selectOne(queryWrapper);
  12. UpdateWrapper<Stock> updateWrapper = new UpdateWrapper<Stock>();
  13. updateWrapper.eq("merch_id",1l);
  14. stock.setCount(stock.getCount()-1);
  15. stockMapper.update(stock,updateWrapper);
  16. System.out.println("扣减库存成功"+merchId);
  17. }
  18. }

7、StockApplication

  1. @SpringBootApplication
  2. @MapperScan("com.suibibk.springCloud.stock.mapper")
  3. public class StockApplication {
  4. public static void main( String[] args ) {
  5. SpringApplication.run(StockApplication.class,args);
  6. }
  7. }

8、application.yml

  1. server:
  2. port: 8014
  3. spring:
  4. application:
  5. name: stock-service
  6. cloud:
  7. nacos:
  8. server-addr: 127.0.0.1:8848
  9. discovery:
  10. username: nacos
  11. password: nacos
  12. namespace: public
  13. datasource:
  14. driver-class-name: com.mysql.cj.jdbc.Driver
  15. url: jdbc:mysql://192.168.192.19:3309/stock_seata?serverTimezone=Asia/Shanghai
  16. username: root
  17. password: 123456
  18. type: com.alibaba.druid.pool.DruidDataSource #Druid类型

五、启动测试

启动后可以看到nacos

访问http://localhost:8013/order/add 可以看到返回

  1. Whitelabel Error Page
  2. This application has no explicit mapping for /error, so you are seeing this as a fallback.
  3. Wed Nov 08 21:01:51 CST 2023
  4. There was an unexpected error (type=Internal Server Error, status=500).

表明执行到了预想中的逻辑1/0,再去看订单库中的订单表和库存库中的库存表,发现订单表没有记录,库存减了1.

达到预期效果,但是业务肯定得保证事务,所以订单下单报错,库存也不能扣减,接下来就尝试使用seata解决这个问题!

可能会遇到feign调用参数传递不过去的问题请注意

  1. FeignClient中的方法有参数传递一般要加@RequestParam(“xxx”)注解
 46

啊!这个可能是世界上最丑的留言输入框功能~


当然,也是最丑的留言列表

有疑问发邮件到 : suibibk@qq.com 侵权立删
Copyright : 个人随笔   备案号 : 粤ICP备18099399号-2