ruoyi-product的ruoyi-product-dev.yml: spring配置 spring: redis: host: localhost port: 6379 password: datasource: druid: stat-view-servlet: enabled: true loginUsername: ruoyi loginPassword: 123456 dynamic: druid: initial-size: 5 min-idle: 5 maxActive: 20 maxWait: 60000 connectTimeout: 30000 socketTimeout: 60000 timeBetweenEvictionRunsMillis: 60000 minEvictableIdleTimeMillis: 300000 validationQuery: SELECT 1 FROM DUAL testWhileIdle: true testOnBorrow: false testOnReturn: false poolPreparedStatements: true maxPoolPreparedStatementPerConnectionSize: 20 filters: stat,slf4j connectionProperties: druid.stat.mergeSql\true;druid.stat.slowSqlMillis\5000 datasource: # 主库数据源 master: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/seata_product?useUnicodetruecharacterEncodingutf8zeroDateTimeBehaviorconvertToNulluseSSLtrueserverTimezoneGMT%2B8 username: root password: root123 # 从库数据源 # slave: # username: # password: # url: # driver-class-name: seata: true # mybatis配置 mybatis: # 搜索指定包别名 typeAliasesPackage: com.ruoyi.product # 配置mapper的扫描找到所有的mapper.xml映射文件 mapperLocations: classpath:mapper/**/*.xml # springdoc配置 springdoc: gatewayUrl: http://localhost:8080/${spring.application.name} api-docs: # 是否开启接口文档 enabled: falseruoyi-product示例代码:Product.javapackage com.ruoyi.product.domain; import lombok.Getter; import lombok.Setter; import java.util.Date; Getter Setter public class Product { private Integer id; /** * 价格 */ private Double price; /** * 库存 */ private Integer stock; private Date lastUpdateTime; }ProductMapper.javapackage com.ruoyi.product.mapper; import com.ruoyi.product.domain.Product; public interface ProductMapper { public Product selectById(Long productId); public void updateById(Product product); }ProductMapper.xml?xml version1.0 encodingUTF-8 ? !DOCTYPE mapper PUBLIC -//mybatis.org//DTD Mapper 3.0//EN http://mybatis.org/dtd/mybatis-3-mapper.dtd mapper namespacecom.ruoyi.product.mapper.ProductMapper resultMap typecom.ruoyi.product.domain.Product idProductResult id propertyid columnid / result propertyprice columnprice / result propertystock columnstock / result propertylastUpdateTime columnlast_update_time / /resultMap select idselectById parameterTypecom.ruoyi.product.domain.Product resultMapProductResult select id, price, stock, last_update_time from product where id #{productId} /select update idupdateById parameterTypecom.ruoyi.product.domain.Product update product set price #{price}, stock #{stock}, last_update_time sysdate() where id #{id} /update /mapperProductService.javapackage com.ruoyi.product.service; public interface ProductService { /** * 扣减库存 * * param productId 商品 ID * param amount 扣减数量 * return 商品总价 */ Double reduceStock(Long productId, Integer amount); }ProductServiceImpl.javapackage com.ruoyi.product.service.impl; import javax.annotation.Resource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; import com.baomidou.dynamic.datasource.annotation.DS; import com.ruoyi.product.domain.Product; import com.ruoyi.product.mapper.ProductMapper; import com.ruoyi.product.service.ProductService; import io.seata.core.context.RootContext; Service public class ProductServiceImpl implements ProductService { private static final Logger log LoggerFactory.getLogger(ProductServiceImpl.class); Resource private ProductMapper productMapper; /** * 事务传播特性设置为 REQUIRES_NEW 开启新的事务 重要一定要使用REQUIRES_NEW * 在若依的示例中事务的传播特性必须设置REQUIRES_NEW但经本人测试多服务调用事务 * 设置成默认的REQUIRED也能回滚成功 */ Transactional Override public Double reduceStock(Long productId, Integer amount) { log.info(PRODUCT START); log.info(当前 XID: {}, RootContext.getXID()); // 检查库存 Product product productMapper.selectById(productId); Integer stock product.getStock(); log.info(商品编号为 {} 的库存为{},订单商品数量为{}, productId, stock, amount); if (stock amount) { log.warn(商品编号为{} 库存不足当前库存:{}, productId, stock); throw new RuntimeException(库存不足); } log.info(开始扣减商品编号为 {} 库存,单价商品价格为{}, productId, product.getPrice()); // 扣减库存 int currentStock stock - amount; product.setStock(currentStock); productMapper.updateById(product); double totalPrice product.getPrice() * amount; log.info(扣减商品编号为 {} 库存成功,扣减后库存为{}, {} 件商品总价为 {} , productId, currentStock, amount, totalPrice); log.info(PRODUCT END); return totalPrice; } }ProductController.javapackage com.ruoyi.product.controller; import com.ruoyi.common.core.domain.R; import com.ruoyi.product.dto.ReduceStockRequest; import com.ruoyi.product.service.ProductService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; RestController RequestMapping(/product) public class ProductController { Autowired private ProductService productService; PostMapping(/reduceStock) public RDouble reduceStock(Validated RequestBody ReduceStockRequest request) { Double d productService.reduceStock(request.getProductId(), request.getAmount()); return R.ok(d); } }ReduceStockRequest.javapackage com.ruoyi.product.dto; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; Getter Setter NoArgsConstructor AllArgsConstructor public class ReduceStockRequest { private Long productId; private Integer amount; }至此商品服务就搭建好了这里主要提供一个扣减商品库存的接口。创建服务调用模块在ruoyi-modules新建一个Moduleruoyi-call当你也可以不新建Module直接把Feign接口写在具调用的服务中这里新建Module主是为了更好的体现模块之间的低耦合该模块主要的作用是提供Feign接口用于订单服务调用商品及账户服务为了搭建方便以及减少Maven依赖pom依赖直接拷贝ruoyi-api-system中的依赖。ruoyi-call的pom.xml:project xmlnshttp://maven.apache.org/POM/4.0.0 xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance xsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd modelVersion4.0.0/modelVersion parent groupIdcom.ruoyi/groupId artifactIdruoyi-modules/artifactId version3.6.6/version /parent artifactIdruoyi-call/artifactId packagingjar/packaging nameruoyi-call/name urlhttp://maven.apache.org/url properties project.build.sourceEncodingUTF-8/project.build.sourceEncoding /properties dependencies dependency groupIdcom.ruoyi/groupId artifactIdruoyi-common-core/artifactId /dependency dependency groupIdorg.projectlombok/groupId artifactIdlombok/artifactId /dependency /dependencies /project