在二十、springCloudAlibaba-seata环境搭建TC(Server端)我们已经搭建好了seata的环境,那么我们这里来搭建一下项目的环境
一、案例
我们打算搭建两个服务,一个订单服务,一个库存服务,分别有自己的数据库,订单服务通过feign调用库存服务。伪代码如下
@Transactionalpublic String add(Long merchId) {System.out.println("新增订单开始"+merchId);Order order = new Order();order.setOrderNo(1l);order.setOrderName("新增订单,对应商品"+merchId);orderMapper.insert(order);System.out.println("新增订单结束"+merchId);//这里是远程调用库存服务扣减库存stockService.reduce(1l);System.out.println("扣减库存结束"+merchId);//这里报错int i =1/0;return null;}
上面开始是在订单数据库插入一条订单数据,然后用feign调用远程库存服务扣减库存,扣减库存完后再执行一个i=1/0;方法触发异常导致该事务回滚,由于没有解决分布式事务的问题,结果应该是订单表没有数据,而库存却扣减成功。下面我们来搭建一下。
二、环境搭建准备
1、参考
五分钟搭建springboot2.7.16+druid+mybatis-plus环境
三、springCloudAlibaba-feign的简单使用
2、订单数据库
CREATE DATABASE order_seata;CREATE TABLE tb_order(order_no BIGINT not null primary key COMMENT '主键ID',order_name VARCHAR(64) COMMENT '订单名字');
3、库存数据库
CREATE DATABASE stock_seata;CREATE TABLE tb_stock(merch_id BIGINT not null primary key COMMENT '主键ID',count BIGINT COMMENT '库存');INSERT INTO `tb_stock` (`merch_id`, `count`) VALUES (1, 100);
三、订单服务代码

1、依赖pom.xml
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!--服务注册与发现 --><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId></dependency><!--数据库配置--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.25</version></dependency><!--数据源--><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.22</version></dependency><!--自动化配置--><dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>1.1.22</version></dependency><!--mybatis-plus --><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.4.2</version></dependency>
2、OrderController
@RestController@RequestMapping("/order")public class OrderController {@AutowiredOrderService orderService;@RequestMapping("/add")public String add(){String msg = orderService.add(1l);return "新增订单成功"+msg;}}
3、OrderMapper
@Repositorypublic interface OrderMapper extends BaseMapper<Order> {}
4、StockService
@FeignClient(name="stock-service",path="/stock")public interface StockService {@RequestMapping("/reduce")public String reduce(@RequestParam("merchId")Long merchId);}
5、Order
@TableName("tb_order")public class Order {@TableField("order_no")private Long orderNo;@TableField("order_name")private String orderName;public Long getOrderNo() {return orderNo;}public void setOrderNo(Long orderNo) {this.orderNo = orderNo;}public String getOrderName() {return orderName;}public void setOrderName(String orderName) {this.orderName = orderName;}@Overridepublic String toString() {return "Order{" +"orderNo=" + orderNo +", orderName='" + orderName + '\'' +'}';}}
6、OrderService
public interface OrderService {public String add(Long merchId);}
7、OrderServiceImpl
@Servicepublic class OrderServiceImpl implements OrderService {@AutowiredStockService stockService;@AutowiredOrderMapper orderMapper;@Transactional@Overridepublic String add(Long merchId) {System.out.println("新增订单开始"+merchId);Order order = new Order();order.setOrderNo(1l);order.setOrderName("新增订单,对应商品"+merchId);orderMapper.insert(order);System.out.println("新增订单结束"+merchId);//新增订单stockService.reduce(1l);System.out.println("扣减库存结束"+merchId);int i =1/0;return null;}}
8、OrderNacosFeignSeataApplication
@SpringBootApplication@MapperScan("com.suibibk.springCloud.order.mapper")@EnableFeignClientspublic class OrderNacosFeignSeataApplication {public static void main( String[] args ) {SpringApplication.run(OrderNacosFeignSeataApplication.class,args);}}
9、application.yml
server:port: 8013spring:application:name: order-nacos-feign-seatacloud:nacos:server-addr: 127.0.0.1:8848discovery:username: nacospassword: nacosnamespace: publicdatasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://192.168.192.19:3309/order_seata?serverTimezone=Asia/Shanghaiusername: rootpassword: 123456type: com.alibaba.druid.pool.DruidDataSource #Druid类型
四、库存服务代码

库存服务暂时不调用别的服务,所以不引入feign
1、引入依赖pom.xml
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!--服务注册与发现 --><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency><!--数据库配置--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.25</version></dependency><!--数据源--><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.22</version></dependency><!--自动化配置--><dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>1.1.22</version></dependency><!--mybatis-plus --><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.4.2</version></dependency>
2、StockController
@RestController@RequestMapping("/stock")public class StockController {@AutowiredStockService stockService;@RequestMapping("/reduce")public String reduce(Long merchId){stockService.reduce(merchId);return "库存扣减成功";}}
3、StockMapper
@Repositorypublic interface StockMapper extends BaseMapper<Stock> {}
4、Stock
@TableName("tb_stock")public class Stock {@TableField("merch_id")private Long merchId;@TableField("count")private Long count;public Long getMerchId() {return merchId;}public void setMerchId(Long merchId) {this.merchId = merchId;}public Long getCount() {return count;}public void setCount(Long count) {this.count = count;}@Overridepublic String toString() {return "Stock{" +"merchId=" + merchId +", count=" + count +'}';}}
5、StockService
public interface StockService {void reduce(Long merchId);}
6、StockServiceImpl
@Servicepublic class StockServiceImpl implements StockService {@AutowiredStockMapper stockMapper;@Transactional@Overridepublic void reduce(Long merchId) {System.out.println("扣减库存开始"+merchId);QueryWrapper<Stock> queryWrapper = new QueryWrapper<Stock>();queryWrapper.eq("merch_id",1l);Stock stock= stockMapper.selectOne(queryWrapper);UpdateWrapper<Stock> updateWrapper = new UpdateWrapper<Stock>();updateWrapper.eq("merch_id",1l);stock.setCount(stock.getCount()-1);stockMapper.update(stock,updateWrapper);System.out.println("扣减库存成功"+merchId);}}
7、StockApplication
@SpringBootApplication@MapperScan("com.suibibk.springCloud.stock.mapper")public class StockApplication {public static void main( String[] args ) {SpringApplication.run(StockApplication.class,args);}}
8、application.yml
server:port: 8014spring:application:name: stock-servicecloud:nacos:server-addr: 127.0.0.1:8848discovery:username: nacospassword: nacosnamespace: publicdatasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://192.168.192.19:3309/stock_seata?serverTimezone=Asia/Shanghaiusername: rootpassword: 123456type: com.alibaba.druid.pool.DruidDataSource #Druid类型
五、启动测试
启动后可以看到nacos
访问http://localhost:8013/order/add 可以看到返回
Whitelabel Error PageThis application has no explicit mapping for /error, so you are seeing this as a fallback.Wed Nov 08 21:01:51 CST 2023There was an unexpected error (type=Internal Server Error, status=500).
表明执行到了预想中的逻辑1/0,再去看订单库中的订单表和库存库中的库存表,发现订单表没有记录,库存减了1.
达到预期效果,但是业务肯定得保证事务,所以订单下单报错,库存也不能扣减,接下来就尝试使用seata解决这个问题!
可能会遇到feign调用参数传递不过去的问题请注意
FeignClient中的方法有参数传递一般要加@RequestParam(“xxx”)注解
