diff --git a/labx-07/labx-07-sca-dubbo-demo01/labx-07-sca-dubbo-demo01-consumer/pom.xml b/labx-07/labx-07-sca-dubbo-demo01/labx-07-sca-dubbo-demo01-consumer/pom.xml index b359af37..c2bf27ef 100644 --- a/labx-07/labx-07-sca-dubbo-demo01/labx-07-sca-dubbo-demo01-consumer/pom.xml +++ b/labx-07/labx-07-sca-dubbo-demo01/labx-07-sca-dubbo-demo01-consumer/pom.xml @@ -20,9 +20,9 @@ + 引入 Spring Boot、Spring Cloud、Spring Cloud Alibaba 三者 BOM 文件,进行依赖版本的管理,防止不兼容。 + 在 https://dwz.cn/mcLIfNKt 文章中,Spring Cloud Alibaba 开发团队推荐了三者的依赖关系 + --> diff --git a/labx-17/labx-17-sca-seata-at-dubbo-demo/lab-53-seata-at-dubbo-demo-order-service-api/pom.xml b/labx-17/labx-17-sca-seata-at-dubbo-demo/lab-53-seata-at-dubbo-demo-order-service-api/pom.xml new file mode 100644 index 00000000..b7c4c049 --- /dev/null +++ b/labx-17/labx-17-sca-seata-at-dubbo-demo/lab-53-seata-at-dubbo-demo-order-service-api/pom.xml @@ -0,0 +1,14 @@ + + + + labx-17-sca-seata-at-dubbo-demo + cn.iocoder.springboot.labs + 1.0-SNAPSHOT + + 4.0.0 + + labx-17-sca-seata-at-dubbo-demo-order-service-api + + diff --git a/labx-17/labx-17-sca-seata-at-dubbo-demo/lab-53-seata-at-dubbo-demo-order-service-api/src/main/java/cn/iocoder/springboot/lab53/orderservice/api/OrderService.java b/labx-17/labx-17-sca-seata-at-dubbo-demo/lab-53-seata-at-dubbo-demo-order-service-api/src/main/java/cn/iocoder/springboot/lab53/orderservice/api/OrderService.java new file mode 100644 index 00000000..34cb0eb8 --- /dev/null +++ b/labx-17/labx-17-sca-seata-at-dubbo-demo/lab-53-seata-at-dubbo-demo-order-service-api/src/main/java/cn/iocoder/springboot/lab53/orderservice/api/OrderService.java @@ -0,0 +1,19 @@ +package cn.iocoder.springboot.lab53.orderservice.api; + +/** + * 订单 Service + */ +public interface OrderService { + + /** + * 创建订单 + * + * @param userId 用户编号 + * @param productId 产品编号 + * @param price 价格 + * @return 订单编号 + * @throws Exception 创建订单失败,抛出异常 + */ + Integer createOrder(Long userId, Long productId, Integer price) throws Exception; + +} diff --git a/labx-17/labx-17-sca-seata-at-dubbo-demo/lab-53-seata-at-dubbo-demo-order-service/pom.xml b/labx-17/labx-17-sca-seata-at-dubbo-demo/lab-53-seata-at-dubbo-demo-order-service/pom.xml new file mode 100644 index 00000000..3c8380b8 --- /dev/null +++ b/labx-17/labx-17-sca-seata-at-dubbo-demo/lab-53-seata-at-dubbo-demo-order-service/pom.xml @@ -0,0 +1,83 @@ + + + + org.springframework.boot + spring-boot-starter-parent + 2.2.2.RELEASE + + + 4.0.0 + + labx-17-sca-seata-at-dubbo-demo-order-service + + + + cn.iocoder.springboot.labs + labx-17-sca-seata-at-dubbo-demo-order-service-api + 1.0-SNAPSHOT + + + cn.iocoder.springboot.labs + labx-17-sca-seata-at-dubbo-demo-account-service-api + 1.0-SNAPSHOT + + + cn.iocoder.springboot.labs + labx-17-sca-seata-at-dubbo-demo-product-service-api + 1.0-SNAPSHOT + + + + + org.springframework.boot + spring-boot-starter-web + + + + + org.springframework.boot + spring-boot-starter-jdbc + + + mysql + mysql-connector-java + 5.1.48 + + + + + org.mybatis.spring.boot + mybatis-spring-boot-starter + 2.1.2 + + + + + io.seata + seata-spring-boot-starter + 1.1.0 + + + + + org.apache.dubbo + dubbo + 2.7.4.1 + + + + org.apache.dubbo + dubbo-spring-boot-starter + 2.7.4.1 + + + + com.alibaba + dubbo-registry-nacos + 2.7.6 + + + + diff --git a/labx-17/labx-17-sca-seata-at-dubbo-demo/lab-53-seata-at-dubbo-demo-order-service/src/main/java/cn/iocoder/springboot/lab53/orderservice/OrderServiceApplication.java b/labx-17/labx-17-sca-seata-at-dubbo-demo/lab-53-seata-at-dubbo-demo-order-service/src/main/java/cn/iocoder/springboot/lab53/orderservice/OrderServiceApplication.java new file mode 100644 index 00000000..bf9b2ddf --- /dev/null +++ b/labx-17/labx-17-sca-seata-at-dubbo-demo/lab-53-seata-at-dubbo-demo-order-service/src/main/java/cn/iocoder/springboot/lab53/orderservice/OrderServiceApplication.java @@ -0,0 +1,13 @@ +package cn.iocoder.springboot.lab53.orderservice; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class OrderServiceApplication { + + public static void main(String[] args) { + SpringApplication.run(OrderServiceApplication.class, args); + } + +} diff --git a/labx-17/labx-17-sca-seata-at-dubbo-demo/lab-53-seata-at-dubbo-demo-order-service/src/main/java/cn/iocoder/springboot/lab53/orderservice/controller/OrderController.java b/labx-17/labx-17-sca-seata-at-dubbo-demo/lab-53-seata-at-dubbo-demo-order-service/src/main/java/cn/iocoder/springboot/lab53/orderservice/controller/OrderController.java new file mode 100644 index 00000000..ccbef5c6 --- /dev/null +++ b/labx-17/labx-17-sca-seata-at-dubbo-demo/lab-53-seata-at-dubbo-demo-order-service/src/main/java/cn/iocoder/springboot/lab53/orderservice/controller/OrderController.java @@ -0,0 +1,29 @@ +package cn.iocoder.springboot.lab53.orderservice.controller; + +import cn.iocoder.springboot.lab53.orderservice.api.OrderService; +import org.apache.dubbo.config.annotation.Reference; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/order") +public class OrderController { + + private Logger logger = LoggerFactory.getLogger(OrderController.class); + + @Reference + private OrderService orderService; + + @PostMapping("/create") + public Integer createOrder(@RequestParam("userId") Long userId, + @RequestParam("productId") Long productId, + @RequestParam("price") Integer price) throws Exception { + logger.info("[createOrder] 收到下单请求,用户:{}, 商品:{}, 价格:{}", userId, productId, price); + return orderService.createOrder(userId, productId, price); + } + +} diff --git a/labx-17/labx-17-sca-seata-at-dubbo-demo/lab-53-seata-at-dubbo-demo-order-service/src/main/java/cn/iocoder/springboot/lab53/orderservice/dao/OrderDao.java b/labx-17/labx-17-sca-seata-at-dubbo-demo/lab-53-seata-at-dubbo-demo-order-service/src/main/java/cn/iocoder/springboot/lab53/orderservice/dao/OrderDao.java new file mode 100644 index 00000000..2c0518bf --- /dev/null +++ b/labx-17/labx-17-sca-seata-at-dubbo-demo/lab-53-seata-at-dubbo-demo-order-service/src/main/java/cn/iocoder/springboot/lab53/orderservice/dao/OrderDao.java @@ -0,0 +1,23 @@ +package cn.iocoder.springboot.lab53.orderservice.dao; + +import cn.iocoder.springboot.lab53.orderservice.entity.OrderDO; +import org.apache.ibatis.annotations.Insert; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Options; +import org.springframework.stereotype.Repository; + +@Mapper +@Repository +public interface OrderDao { + + /** + * 插入订单记录 + * + * @param order 订单 + * @return 影响记录数量 + */ + @Insert("INSERT INTO orders (user_id, product_id, pay_amount) VALUES (#{userId}, #{productId}, #{payAmount})") + @Options(useGeneratedKeys = true, keyColumn = "id", keyProperty = "id") + int saveOrder(OrderDO order); + +} diff --git a/labx-17/labx-17-sca-seata-at-dubbo-demo/lab-53-seata-at-dubbo-demo-order-service/src/main/java/cn/iocoder/springboot/lab53/orderservice/entity/OrderDO.java b/labx-17/labx-17-sca-seata-at-dubbo-demo/lab-53-seata-at-dubbo-demo-order-service/src/main/java/cn/iocoder/springboot/lab53/orderservice/entity/OrderDO.java new file mode 100644 index 00000000..4ff509e4 --- /dev/null +++ b/labx-17/labx-17-sca-seata-at-dubbo-demo/lab-53-seata-at-dubbo-demo-order-service/src/main/java/cn/iocoder/springboot/lab53/orderservice/entity/OrderDO.java @@ -0,0 +1,56 @@ +package cn.iocoder.springboot.lab53.orderservice.entity; + +/** + * 订单实体 + */ +public class OrderDO { + + /** 订单编号 **/ + private Integer id; + + /** 用户编号 **/ + private Long userId; + + /** 产品编号 **/ + private Long productId; + + /** 支付金额 **/ + private Integer payAmount; + + public Integer getId() { + return id; + } + + public OrderDO setId(Integer id) { + this.id = id; + return this; + } + + public Long getUserId() { + return userId; + } + + public OrderDO setUserId(Long userId) { + this.userId = userId; + return this; + } + + public Long getProductId() { + return productId; + } + + public OrderDO setProductId(Long productId) { + this.productId = productId; + return this; + } + + public Integer getPayAmount() { + return payAmount; + } + + public OrderDO setPayAmount(Integer payAmount) { + this.payAmount = payAmount; + return this; + } + +} diff --git a/labx-17/labx-17-sca-seata-at-dubbo-demo/lab-53-seata-at-dubbo-demo-order-service/src/main/java/cn/iocoder/springboot/lab53/orderservice/service/OrderServiceImpl.java b/labx-17/labx-17-sca-seata-at-dubbo-demo/lab-53-seata-at-dubbo-demo-order-service/src/main/java/cn/iocoder/springboot/lab53/orderservice/service/OrderServiceImpl.java new file mode 100644 index 00000000..a7e32e34 --- /dev/null +++ b/labx-17/labx-17-sca-seata-at-dubbo-demo/lab-53-seata-at-dubbo-demo-order-service/src/main/java/cn/iocoder/springboot/lab53/orderservice/service/OrderServiceImpl.java @@ -0,0 +1,50 @@ +package cn.iocoder.springboot.lab53.orderservice.service; + +import cn.iocoder.springboot.lab53.accountservice.api.AccountService; +import cn.iocoder.springboot.lab53.orderservice.api.OrderService; +import cn.iocoder.springboot.lab53.orderservice.dao.OrderDao; +import cn.iocoder.springboot.lab53.orderservice.entity.OrderDO; +import cn.iocoder.springboot.lab53.storageservice.api.ProductService; +import io.seata.core.context.RootContext; +import io.seata.spring.annotation.GlobalTransactional; +import org.apache.dubbo.config.annotation.Reference; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; + +@org.apache.dubbo.config.annotation.Service +public class OrderServiceImpl implements OrderService { + + private Logger logger = LoggerFactory.getLogger(getClass()); + + @Autowired + private OrderDao orderDao; + + @Reference + private AccountService accountService; + @Reference + private ProductService productService; + + @Override + @GlobalTransactional + public Integer createOrder(Long userId, Long productId, Integer price) throws Exception { + Integer amount = 1; // 购买数量,暂时设置为 1。 + + logger.info("[createOrder] 当前 XID: {}", RootContext.getXID()); + + // 扣减库存 + productService.reduceStock(productId, amount); + + // 扣减余额 + accountService.reduceBalance(userId, price); + + // 保存订单 + OrderDO order = new OrderDO().setUserId(userId).setProductId(productId).setPayAmount(amount * price); + orderDao.saveOrder(order); + logger.info("[createOrder] 保存订单: {}", order.getId()); + + // 返回订单编号 + return order.getId(); + } + +} diff --git a/labx-17/labx-17-sca-seata-at-dubbo-demo/lab-53-seata-at-dubbo-demo-order-service/src/main/resources/application-file.yaml b/labx-17/labx-17-sca-seata-at-dubbo-demo/lab-53-seata-at-dubbo-demo-order-service/src/main/resources/application-file.yaml new file mode 100644 index 00000000..b8616381 --- /dev/null +++ b/labx-17/labx-17-sca-seata-at-dubbo-demo/lab-53-seata-at-dubbo-demo-order-service/src/main/resources/application-file.yaml @@ -0,0 +1,41 @@ +server: + port: 8081 # 端口 + +spring: + application: + name: order-service + + datasource: + url: jdbc:mysql://127.0.0.1:3306/seata_order?useSSL=false&useUnicode=true&characterEncoding=UTF-8 + driver-class-name: com.mysql.jdbc.Driver + username: root + password: + +# dubbo 配置项,对应 DubboConfigurationProperties 配置类 +dubbo: + # Dubbo 应用配置 + application: + name: ${spring.application.name} # 应用名 + # Dubbo 注册中心配 + registry: + address: nacos://127.0.0.1:8848 # 注册中心地址。个鞥多注册中心,可见 http://dubbo.apache.org/zh-cn/docs/user/references/registry/introduction.html 文档。 + # Dubbo 服务提供者协议配置 + protocol: + port: -1 # 协议端口。使用 -1 表示随机端口。 + name: dubbo # 使用 `dubbo://` 协议。更多协议,可见 http://dubbo.apache.org/zh-cn/docs/user/references/protocol/introduction.html 文档 + # 配置扫描 Dubbo 自定义的 @Service 注解,暴露成 Dubbo 服务提供者 + scan: + base-packages: cn.iocoder.springboot.lab53.orderservice.service + +# Seata 配置项,对应 SeataProperties 类 +seata: + application-id: ${spring.application.name} # Seata 应用编号,默认为 ${spring.application.name} + tx-service-group: ${spring.application.name}-group # Seata 事务组编号,用于 TC 集群名 + # 服务配置项,对应 ServiceProperties 类 + service: + # 虚拟组和分组的映射 + vgroup-mapping: + order-service-group: default + # 分组和 Seata 服务的映射 + grouplist: + default: 127.0.0.1:8091 diff --git a/labx-17/labx-17-sca-seata-at-dubbo-demo/lab-53-seata-at-dubbo-demo-order-service/src/main/resources/application.yaml b/labx-17/labx-17-sca-seata-at-dubbo-demo/lab-53-seata-at-dubbo-demo-order-service/src/main/resources/application.yaml new file mode 100644 index 00000000..9ff3e7c8 --- /dev/null +++ b/labx-17/labx-17-sca-seata-at-dubbo-demo/lab-53-seata-at-dubbo-demo-order-service/src/main/resources/application.yaml @@ -0,0 +1,45 @@ +server: + port: 8081 # 端口 + +spring: + application: + name: order-service + + datasource: + url: jdbc:mysql://127.0.0.1:3306/seata_order?useSSL=false&useUnicode=true&characterEncoding=UTF-8 + driver-class-name: com.mysql.jdbc.Driver + username: root + password: + +# dubbo 配置项,对应 DubboConfigurationProperties 配置类 +dubbo: + # Dubbo 应用配置 + application: + name: ${spring.application.name} # 应用名 + # Dubbo 注册中心配 + registry: + address: nacos://127.0.0.1:8848 # 注册中心地址。个鞥多注册中心,可见 http://dubbo.apache.org/zh-cn/docs/user/references/registry/introduction.html 文档。 + # Dubbo 服务提供者协议配置 + protocol: + port: -1 # 协议端口。使用 -1 表示随机端口。 + name: dubbo # 使用 `dubbo://` 协议。更多协议,可见 http://dubbo.apache.org/zh-cn/docs/user/references/protocol/introduction.html 文档 + # 配置扫描 Dubbo 自定义的 @Service 注解,暴露成 Dubbo 服务提供者 + scan: + base-packages: cn.iocoder.springboot.lab53.orderservice.service + +# Seata 配置项,对应 SeataProperties 类 +seata: + application-id: ${spring.application.name} # Seata 应用编号,默认为 ${spring.application.name} + tx-service-group: ${spring.application.name}-group # Seata 事务组编号,用于 TC 集群名 + # Seata 服务配置项,对应 ServiceProperties 类 + service: + # 虚拟组和分组的映射 + vgroup-mapping: + order-service-group: default + # Seata 注册中心配置项,对应 RegistryProperties 类 + registry: + type: nacos # 注册中心类型,默认为 file + nacos: + cluster: default # 使用的 Seata 分组 + namespace: # Nacos 命名空间 + serverAddr: localhost # Nacos 服务地址 diff --git a/labx-17/labx-17-sca-seata-at-dubbo-demo/lab-53-seata-at-dubbo-demo-product-service-api/pom.xml b/labx-17/labx-17-sca-seata-at-dubbo-demo/lab-53-seata-at-dubbo-demo-product-service-api/pom.xml new file mode 100644 index 00000000..61a9e55c --- /dev/null +++ b/labx-17/labx-17-sca-seata-at-dubbo-demo/lab-53-seata-at-dubbo-demo-product-service-api/pom.xml @@ -0,0 +1,14 @@ + + + + labx-17-sca-seata-at-dubbo-demo + cn.iocoder.springboot.labs + 1.0-SNAPSHOT + + 4.0.0 + + labx-17-sca-seata-at-dubbo-demo-product-service-api + + diff --git a/labx-17/labx-17-sca-seata-at-dubbo-demo/lab-53-seata-at-dubbo-demo-product-service-api/src/main/java/cn/iocoder/springboot/lab53/storageservice/api/ProductService.java b/labx-17/labx-17-sca-seata-at-dubbo-demo/lab-53-seata-at-dubbo-demo-product-service-api/src/main/java/cn/iocoder/springboot/lab53/storageservice/api/ProductService.java new file mode 100644 index 00000000..01e06909 --- /dev/null +++ b/labx-17/labx-17-sca-seata-at-dubbo-demo/lab-53-seata-at-dubbo-demo-product-service-api/src/main/java/cn/iocoder/springboot/lab53/storageservice/api/ProductService.java @@ -0,0 +1,17 @@ +package cn.iocoder.springboot.lab53.storageservice.api; + +/** + * 商品 Service + */ +public interface ProductService { + + /** + * 扣减库存 + * + * @param productId 商品 ID + * @param amount 扣减数量 + * @throws Exception 扣减失败时抛出异常 + */ + void reduceStock(Long productId, Integer amount) throws Exception; + +} diff --git a/labx-17/labx-17-sca-seata-at-dubbo-demo/lab-53-seata-at-dubbo-demo-product-service/pom.xml b/labx-17/labx-17-sca-seata-at-dubbo-demo/lab-53-seata-at-dubbo-demo-product-service/pom.xml new file mode 100644 index 00000000..14004fc3 --- /dev/null +++ b/labx-17/labx-17-sca-seata-at-dubbo-demo/lab-53-seata-at-dubbo-demo-product-service/pom.xml @@ -0,0 +1,73 @@ + + + + org.springframework.boot + spring-boot-starter-parent + 2.2.2.RELEASE + + + 4.0.0 + + labx-17-sca-seata-at-dubbo-demo-product-service + + + + cn.iocoder.springboot.labs + labx-17-sca-seata-at-dubbo-demo-product-service-api + 1.0-SNAPSHOT + + + + + org.springframework.boot + spring-boot-starter + + + + + org.springframework.boot + spring-boot-starter-jdbc + + + mysql + mysql-connector-java + 5.1.48 + + + + + org.mybatis.spring.boot + mybatis-spring-boot-starter + 2.1.2 + + + + + io.seata + seata-spring-boot-starter + 1.1.0 + + + + + org.apache.dubbo + dubbo + 2.7.4.1 + + + + org.apache.dubbo + dubbo-spring-boot-starter + 2.7.4.1 + + + + com.alibaba + dubbo-registry-nacos + 2.7.6 + + + + diff --git a/labx-17/labx-17-sca-seata-at-dubbo-demo/lab-53-seata-at-dubbo-demo-product-service/src/main/java/cn/iocoder/springboot/lab53/productservice/ProductServiceApplication.java b/labx-17/labx-17-sca-seata-at-dubbo-demo/lab-53-seata-at-dubbo-demo-product-service/src/main/java/cn/iocoder/springboot/lab53/productservice/ProductServiceApplication.java new file mode 100644 index 00000000..0f286bb1 --- /dev/null +++ b/labx-17/labx-17-sca-seata-at-dubbo-demo/lab-53-seata-at-dubbo-demo-product-service/src/main/java/cn/iocoder/springboot/lab53/productservice/ProductServiceApplication.java @@ -0,0 +1,13 @@ +package cn.iocoder.springboot.lab53.productservice; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class ProductServiceApplication { + + public static void main(String[] args) { + SpringApplication.run(ProductServiceApplication.class, args); + } + +} diff --git a/labx-17/labx-17-sca-seata-at-dubbo-demo/lab-53-seata-at-dubbo-demo-product-service/src/main/java/cn/iocoder/springboot/lab53/productservice/dao/ProductDao.java b/labx-17/labx-17-sca-seata-at-dubbo-demo/lab-53-seata-at-dubbo-demo-product-service/src/main/java/cn/iocoder/springboot/lab53/productservice/dao/ProductDao.java new file mode 100644 index 00000000..df404727 --- /dev/null +++ b/labx-17/labx-17-sca-seata-at-dubbo-demo/lab-53-seata-at-dubbo-demo-product-service/src/main/java/cn/iocoder/springboot/lab53/productservice/dao/ProductDao.java @@ -0,0 +1,33 @@ +package cn.iocoder.springboot.lab53.productservice.dao; + + +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; +import org.apache.ibatis.annotations.Update; +import org.springframework.stereotype.Repository; + +@Mapper +@Repository +public interface ProductDao { + + /** + * 获取库存 + * + * @param productId 商品编号 + * @return 库存 + */ + @Select("SELECT stock FROM product WHERE id = #{productId}") + Integer getStock(@Param("productId") Long productId); + + /** + * 扣减库存 + * + * @param productId 商品编号 + * @param amount 扣减数量 + * @return 影响记录行数 + */ + @Update("UPDATE product SET stock = stock - #{amount} WHERE id = #{productId} AND stock >= #{amount}") + int reduceStock(@Param("productId") Long productId, @Param("amount") Integer amount); + +} diff --git a/labx-17/labx-17-sca-seata-at-dubbo-demo/lab-53-seata-at-dubbo-demo-product-service/src/main/java/cn/iocoder/springboot/lab53/productservice/service/ProductServiceImpl.java b/labx-17/labx-17-sca-seata-at-dubbo-demo/lab-53-seata-at-dubbo-demo-product-service/src/main/java/cn/iocoder/springboot/lab53/productservice/service/ProductServiceImpl.java new file mode 100644 index 00000000..f864becf --- /dev/null +++ b/labx-17/labx-17-sca-seata-at-dubbo-demo/lab-53-seata-at-dubbo-demo-product-service/src/main/java/cn/iocoder/springboot/lab53/productservice/service/ProductServiceImpl.java @@ -0,0 +1,48 @@ +package cn.iocoder.springboot.lab53.productservice.service; + +import cn.iocoder.springboot.lab53.productservice.dao.ProductDao; +import cn.iocoder.springboot.lab53.storageservice.api.ProductService; +import io.seata.core.context.RootContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.transaction.annotation.Transactional; + +@org.apache.dubbo.config.annotation.Service +public class ProductServiceImpl implements ProductService { + + private Logger logger = LoggerFactory.getLogger(getClass()); + + @Autowired + private ProductDao productDao; + + @Override + @Transactional // 开启新事物 + public void reduceStock(Long productId, Integer amount) throws Exception { + logger.info("[reduceStock] 当前 XID: {}", RootContext.getXID()); + + // 检查库存 + checkStock(productId, amount); + + logger.info("[reduceStock] 开始扣减 {} 库存", productId); + // 扣减库存 + int updateCount = productDao.reduceStock(productId, amount); + // 扣除成功 + if (updateCount == 0) { + logger.warn("[reduceStock] 扣除 {} 库存失败", productId); + throw new Exception("库存不足"); + } + // 扣除失败 + logger.info("[reduceStock] 扣除 {} 库存成功", productId); + } + + private void checkStock(Long productId, Integer requiredAmount) throws Exception { + logger.info("[checkStock] 检查 {} 库存", productId); + Integer stock = productDao.getStock(productId); + if (stock < requiredAmount) { + logger.warn("[checkStock] {} 库存不足,当前库存: {}", productId, stock); + throw new Exception("库存不足"); + } + } + +} diff --git a/labx-17/labx-17-sca-seata-at-dubbo-demo/lab-53-seata-at-dubbo-demo-product-service/src/main/resources/application-file.yaml b/labx-17/labx-17-sca-seata-at-dubbo-demo/lab-53-seata-at-dubbo-demo-product-service/src/main/resources/application-file.yaml new file mode 100644 index 00000000..63068ae2 --- /dev/null +++ b/labx-17/labx-17-sca-seata-at-dubbo-demo/lab-53-seata-at-dubbo-demo-product-service/src/main/resources/application-file.yaml @@ -0,0 +1,38 @@ +spring: + application: + name: product-service + + datasource: + url: jdbc:mysql://127.0.0.1:3306/seata_product?useSSL=false&useUnicode=true&characterEncoding=UTF-8 + driver-class-name: com.mysql.jdbc.Driver + username: root + password: + +# dubbo 配置项,对应 DubboConfigurationProperties 配置类 +dubbo: + # Dubbo 应用配置 + application: + name: ${spring.application.name} # 应用名 + # Dubbo 注册中心配 + registry: + address: nacos://127.0.0.1:8848 # 注册中心地址。个鞥多注册中心,可见 http://dubbo.apache.org/zh-cn/docs/user/references/registry/introduction.html 文档。 + # Dubbo 服务提供者协议配置 + protocol: + port: -1 # 协议端口。使用 -1 表示随机端口。 + name: dubbo # 使用 `dubbo://` 协议。更多协议,可见 http://dubbo.apache.org/zh-cn/docs/user/references/protocol/introduction.html 文档 + # 配置扫描 Dubbo 自定义的 @Service 注解,暴露成 Dubbo 服务提供者 + scan: + base-packages: cn.iocoder.springboot.lab53.productservice.service + +# Seata 配置项,对应 SeataProperties 类 +seata: + application-id: ${spring.application.name} # Seata 应用编号,默认为 ${spring.application.name} + tx-service-group: ${spring.application.name}-group # Seata 事务组编号,用于 TC 集群名 + # 服务配置项,对应 ServiceProperties 类 + service: + # 虚拟组和分组的映射 + vgroup-mapping: + product-service-group: default + # 分组和 Seata 服务的映射 + grouplist: + default: 127.0.0.1:8091 diff --git a/labx-17/labx-17-sca-seata-at-dubbo-demo/lab-53-seata-at-dubbo-demo-product-service/src/main/resources/application.yaml b/labx-17/labx-17-sca-seata-at-dubbo-demo/lab-53-seata-at-dubbo-demo-product-service/src/main/resources/application.yaml new file mode 100644 index 00000000..614d80a6 --- /dev/null +++ b/labx-17/labx-17-sca-seata-at-dubbo-demo/lab-53-seata-at-dubbo-demo-product-service/src/main/resources/application.yaml @@ -0,0 +1,42 @@ +spring: + application: + name: product-service + + datasource: + url: jdbc:mysql://127.0.0.1:3306/seata_product?useSSL=false&useUnicode=true&characterEncoding=UTF-8 + driver-class-name: com.mysql.jdbc.Driver + username: root + password: + +# dubbo 配置项,对应 DubboConfigurationProperties 配置类 +dubbo: + # Dubbo 应用配置 + application: + name: ${spring.application.name} # 应用名 + # Dubbo 注册中心配 + registry: + address: nacos://127.0.0.1:8848 # 注册中心地址。个鞥多注册中心,可见 http://dubbo.apache.org/zh-cn/docs/user/references/registry/introduction.html 文档。 + # Dubbo 服务提供者协议配置 + protocol: + port: -1 # 协议端口。使用 -1 表示随机端口。 + name: dubbo # 使用 `dubbo://` 协议。更多协议,可见 http://dubbo.apache.org/zh-cn/docs/user/references/protocol/introduction.html 文档 + # 配置扫描 Dubbo 自定义的 @Service 注解,暴露成 Dubbo 服务提供者 + scan: + base-packages: cn.iocoder.springboot.lab53.productservice.service + +# Seata 配置项,对应 SeataProperties 类 +seata: + application-id: ${spring.application.name} # Seata 应用编号,默认为 ${spring.application.name} + tx-service-group: ${spring.application.name}-group # Seata 事务组编号,用于 TC 集群名 + # Seata 服务配置项,对应 ServiceProperties 类 + service: + # 虚拟组和分组的映射 + vgroup-mapping: + product-service-group: default + # Seata 注册中心配置项,对应 RegistryProperties 类 + registry: + type: nacos # 注册中心类型,默认为 file + nacos: + cluster: default # 使用的 Seata 分组 + namespace: # Nacos 命名空间 + serverAddr: localhost # Nacos 服务地址 diff --git a/labx-17/labx-17-sca-seata-at-dubbo-demo/labx-17-sca-seata-at-dubbo-demo-account-service-api/pom.xml b/labx-17/labx-17-sca-seata-at-dubbo-demo/labx-17-sca-seata-at-dubbo-demo-account-service-api/pom.xml new file mode 100644 index 00000000..75b20375 --- /dev/null +++ b/labx-17/labx-17-sca-seata-at-dubbo-demo/labx-17-sca-seata-at-dubbo-demo-account-service-api/pom.xml @@ -0,0 +1,14 @@ + + + + labx-17-sca-seata-at-dubbo-demo + cn.iocoder.springboot.labs + 1.0-SNAPSHOT + + 4.0.0 + + labx-17-sca-seata-at-dubbo-demo-account-service-api + + diff --git a/labx-17/labx-17-sca-seata-at-dubbo-demo/labx-17-sca-seata-at-dubbo-demo-account-service-api/src/main/java/cn/iocoder/springcloudalibaba/labx17/accountservice/api/AccountService.java b/labx-17/labx-17-sca-seata-at-dubbo-demo/labx-17-sca-seata-at-dubbo-demo-account-service-api/src/main/java/cn/iocoder/springcloudalibaba/labx17/accountservice/api/AccountService.java new file mode 100644 index 00000000..b4f8b229 --- /dev/null +++ b/labx-17/labx-17-sca-seata-at-dubbo-demo/labx-17-sca-seata-at-dubbo-demo-account-service-api/src/main/java/cn/iocoder/springcloudalibaba/labx17/accountservice/api/AccountService.java @@ -0,0 +1,17 @@ +package cn.iocoder.springcloudalibaba.labx17.accountservice.api; + +/** + * 账户 Service + */ +public interface AccountService { + + /** + * 扣除余额 + * + * @param userId 用户编号 + * @param price 扣减金额 + * @throws Exception 失败时抛出异常 + */ + void reduceBalance(Long userId, Integer price) throws Exception; + +} diff --git a/labx-17/labx-17-sca-seata-at-dubbo-demo/labx-17-sca-seata-at-dubbo-demo-account-service/pom.xml b/labx-17/labx-17-sca-seata-at-dubbo-demo/labx-17-sca-seata-at-dubbo-demo-account-service/pom.xml new file mode 100644 index 00000000..96f526cd --- /dev/null +++ b/labx-17/labx-17-sca-seata-at-dubbo-demo/labx-17-sca-seata-at-dubbo-demo-account-service/pom.xml @@ -0,0 +1,107 @@ + + + + labx-17-sca-seata-at-dubbo-demo + cn.iocoder.springboot.labs + 1.0-SNAPSHOT + + 4.0.0 + + labx-17-sca-seata-at-dubbo-demo-account-service + + + 1.8 + 1.8 + 2.2.4.RELEASE + Hoxton.SR1 + 2.2.0.RELEASE + + + + + + + org.springframework.boot + spring-boot-starter-parent + ${spring.boot.version} + pom + import + + + org.springframework.cloud + spring-cloud-dependencies + ${spring.cloud.version} + pom + import + + + com.alibaba.cloud + spring-cloud-alibaba-dependencies + ${spring.cloud.alibaba.version} + pom + import + + + + + + + cn.iocoder.springboot.labs + labx-17-sca-seata-at-dubbo-demo-account-service-api + 1.0-SNAPSHOT + + + + + org.springframework.boot + spring-boot-starter + + + + + org.springframework.boot + spring-boot-starter-jdbc + + + mysql + mysql-connector-java + 5.1.48 + + + com.alibaba + druid-spring-boot-starter + 1.1.10 + + + + + org.mybatis.spring.boot + mybatis-spring-boot-starter + 2.1.2 + + + + + com.alibaba.cloud + spring-cloud-alibaba-seata + + + + + com.alibaba.cloud + spring-cloud-starter-alibaba-nacos-discovery + + + + + com.alibaba.cloud + spring-cloud-starter-dubbo + + + + diff --git a/labx-17/labx-17-sca-seata-at-dubbo-demo/labx-17-sca-seata-at-dubbo-demo-account-service/src/main/java/cn/iocoder/springcloudalibaba/labx17/accountservice/AccountServiceApplication.java b/labx-17/labx-17-sca-seata-at-dubbo-demo/labx-17-sca-seata-at-dubbo-demo-account-service/src/main/java/cn/iocoder/springcloudalibaba/labx17/accountservice/AccountServiceApplication.java new file mode 100644 index 00000000..3e86cc58 --- /dev/null +++ b/labx-17/labx-17-sca-seata-at-dubbo-demo/labx-17-sca-seata-at-dubbo-demo-account-service/src/main/java/cn/iocoder/springcloudalibaba/labx17/accountservice/AccountServiceApplication.java @@ -0,0 +1,13 @@ +package cn.iocoder.springcloudalibaba.labx17.accountservice; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class AccountServiceApplication { + + public static void main(String[] args) { + SpringApplication.run(AccountServiceApplication.class, args); + } + +} diff --git a/labx-17/labx-17-sca-seata-at-dubbo-demo/labx-17-sca-seata-at-dubbo-demo-account-service/src/main/java/cn/iocoder/springcloudalibaba/labx17/accountservice/dao/AccountDao.java b/labx-17/labx-17-sca-seata-at-dubbo-demo/labx-17-sca-seata-at-dubbo-demo-account-service/src/main/java/cn/iocoder/springcloudalibaba/labx17/accountservice/dao/AccountDao.java new file mode 100644 index 00000000..0b3081c6 --- /dev/null +++ b/labx-17/labx-17-sca-seata-at-dubbo-demo/labx-17-sca-seata-at-dubbo-demo-account-service/src/main/java/cn/iocoder/springcloudalibaba/labx17/accountservice/dao/AccountDao.java @@ -0,0 +1,32 @@ +package cn.iocoder.springcloudalibaba.labx17.accountservice.dao; + + +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; +import org.apache.ibatis.annotations.Update; +import org.springframework.stereotype.Repository; + +@Mapper +@Repository +public interface AccountDao { + + /** + * 获取账户余额 + * + * @param userId 用户 ID + * @return 账户余额 + */ + @Select("SELECT balance FROM account WHERE id = #{userId}") + Integer getBalance(@Param("userId") Long userId); + + /** + * 扣减余额 + * + * @param price 需要扣减的数目 + * @return 影响记录行数 + */ + @Update("UPDATE account SET balance = balance - #{price} WHERE id = 1 AND balance >= ${price}") + int reduceBalance(@Param("price") Integer price); + +} diff --git a/labx-17/labx-17-sca-seata-at-dubbo-demo/labx-17-sca-seata-at-dubbo-demo-account-service/src/main/java/cn/iocoder/springcloudalibaba/labx17/accountservice/service/AccountServiceImpl.java b/labx-17/labx-17-sca-seata-at-dubbo-demo/labx-17-sca-seata-at-dubbo-demo-account-service/src/main/java/cn/iocoder/springcloudalibaba/labx17/accountservice/service/AccountServiceImpl.java new file mode 100644 index 00000000..2f5c3cbf --- /dev/null +++ b/labx-17/labx-17-sca-seata-at-dubbo-demo/labx-17-sca-seata-at-dubbo-demo-account-service/src/main/java/cn/iocoder/springcloudalibaba/labx17/accountservice/service/AccountServiceImpl.java @@ -0,0 +1,47 @@ +package cn.iocoder.springcloudalibaba.labx17.accountservice.service; + +import cn.iocoder.springcloudalibaba.labx17.accountservice.api.AccountService; +import cn.iocoder.springcloudalibaba.labx17.accountservice.dao.AccountDao; +import io.seata.core.context.RootContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.transaction.annotation.Transactional; + +@org.apache.dubbo.config.annotation.Service +public class AccountServiceImpl implements AccountService { + + private Logger logger = LoggerFactory.getLogger(getClass()); + + @Autowired + private AccountDao accountDao; + + @Override + @Transactional // 开启新事物 + public void reduceBalance(Long userId, Integer price) throws Exception { + logger.info("[reduceBalance] 当前 XID: {}", RootContext.getXID()); + + // 检查余额 + checkBalance(userId, price); + + logger.info("[reduceBalance] 开始扣减用户 {} 余额", userId); + // 扣除余额 + int updateCount = accountDao.reduceBalance(price); + // 扣除成功 + if (updateCount == 0) { + logger.warn("[reduceBalance] 扣除用户 {} 余额失败", userId); + throw new Exception("余额不足"); + } + logger.info("[reduceBalance] 扣除用户 {} 余额成功", userId); + } + + private void checkBalance(Long userId, Integer price) throws Exception { + logger.info("[checkBalance] 检查用户 {} 余额", userId); + Integer balance = accountDao.getBalance(userId); + if (balance < price) { + logger.warn("[checkBalance] 用户 {} 余额不足,当前余额:{}", userId, balance); + throw new Exception("余额不足"); + } + } + +} diff --git a/labx-17/labx-17-sca-seata-at-dubbo-demo/labx-17-sca-seata-at-dubbo-demo-account-service/src/main/resources/application-file.yaml b/labx-17/labx-17-sca-seata-at-dubbo-demo/labx-17-sca-seata-at-dubbo-demo-account-service/src/main/resources/application-file.yaml new file mode 100644 index 00000000..85d71970 --- /dev/null +++ b/labx-17/labx-17-sca-seata-at-dubbo-demo/labx-17-sca-seata-at-dubbo-demo-account-service/src/main/resources/application-file.yaml @@ -0,0 +1,38 @@ +spring: + application: + name: account-service + + datasource: + url: jdbc:mysql://127.0.0.1:3306/seata_account?useSSL=false&useUnicode=true&characterEncoding=UTF-8 + driver-class-name: com.mysql.jdbc.Driver + username: root + password: + +# dubbo 配置项,对应 DubboConfigurationProperties 配置类 +dubbo: + # Dubbo 应用配置 + application: + name: ${spring.application.name} # 应用名 + # Dubbo 注册中心配 + registry: + address: nacos://127.0.0.1:8848 # 注册中心地址。个鞥多注册中心,可见 http://dubbo.apache.org/zh-cn/docs/user/references/registry/introduction.html 文档。 + # Dubbo 服务提供者协议配置 + protocol: + port: -1 # 协议端口。使用 -1 表示随机端口。 + name: dubbo # 使用 `dubbo://` 协议。更多协议,可见 http://dubbo.apache.org/zh-cn/docs/user/references/protocol/introduction.html 文档 + # 配置扫描 Dubbo 自定义的 @Service 注解,暴露成 Dubbo 服务提供者 + scan: + base-packages: cn.iocoder.springboot.lab53.accountservice.service + +# Seata 配置项,对应 SeataProperties 类 +seata: + application-id: ${spring.application.name} # Seata 应用编号,默认为 ${spring.application.name} + tx-service-group: ${spring.application.name}-group # Seata 事务组编号,用于 TC 集群名 + # 服务配置项,对应 ServiceProperties 类 + service: + # 虚拟组和分组的映射 + vgroup-mapping: + account-service-group: default + # 分组和 Seata 服务的映射 + grouplist: + default: 127.0.0.1:8091 diff --git a/labx-17/labx-17-sca-seata-at-dubbo-demo/labx-17-sca-seata-at-dubbo-demo-account-service/src/main/resources/application.yaml b/labx-17/labx-17-sca-seata-at-dubbo-demo/labx-17-sca-seata-at-dubbo-demo-account-service/src/main/resources/application.yaml new file mode 100644 index 00000000..5bf1b266 --- /dev/null +++ b/labx-17/labx-17-sca-seata-at-dubbo-demo/labx-17-sca-seata-at-dubbo-demo-account-service/src/main/resources/application.yaml @@ -0,0 +1,48 @@ +spring: + application: + name: account-service + + datasource: + url: jdbc:mysql://127.0.0.1:3306/seata_account?useSSL=false&useUnicode=true&characterEncoding=UTF-8 + driver-class-name: com.mysql.jdbc.Driver + username: root + password: + + cloud: + # Nacos 作为注册中心的配置项 + nacos: + discovery: + server-addr: 127.0.0.1:8848 + +# dubbo 配置项,对应 DubboConfigurationProperties 配置类 +dubbo: + # Dubbo 服务注册中心配置,对应 RegistryConfig 类 + registry: + address: spring-cloud://127.0.0.1:8848 # 指定 Dubbo 服务注册中心的地址 + # Dubbo 服务提供者协议配置 + protocol: + port: -1 # 协议端口。使用 -1 表示随机端口。 + name: dubbo # 使用 `dubbo://` 协议。更多协议,可见 http://dubbo.apache.org/zh-cn/docs/user/references/protocol/introduction.html 文档 + # 配置扫描 Dubbo 自定义的 @Service 注解,暴露成 Dubbo 服务提供者 + scan: + base-packages: cn.iocoder.springcloudalibaba.labx17.accountservice.service + # Spring Cloud Alibaba Dubbo 专属配置项,对应 DubboCloudProperties 类 + cloud: + subscribed-services: '' # 设置订阅的应用列表,默认为 * 订阅所有应用。 + +# Seata 配置项,对应 SeataProperties 类 +seata: + application-id: ${spring.application.name} # Seata 应用编号,默认为 ${spring.application.name} + tx-service-group: ${spring.application.name}-group # Seata 事务组编号,用于 TC 集群名 + # Seata 服务配置项,对应 ServiceProperties 类 + service: + # 虚拟组和分组的映射 + vgroup-mapping: + account-service-group: default + # Seata 注册中心配置项,对应 RegistryProperties 类 + registry: + type: nacos # 注册中心类型,默认为 file + nacos: + cluster: default # 使用的 Seata 分组 + namespace: # Nacos 命名空间 + serverAddr: localhost # Nacos 服务地址 diff --git a/labx-17/labx-17-sca-seata-at-dubbo-demo/pom.xml b/labx-17/labx-17-sca-seata-at-dubbo-demo/pom.xml new file mode 100644 index 00000000..f8331c92 --- /dev/null +++ b/labx-17/labx-17-sca-seata-at-dubbo-demo/pom.xml @@ -0,0 +1,19 @@ + + + + labx-17 + cn.iocoder.springboot.labs + 1.0-SNAPSHOT + + 4.0.0 + + labx-17-sca-seata-at-dubbo-demo + + + labx-17-sca-seata-at-dubbo-demo-account-service-api + labx-17-sca-seata-at-dubbo-demo-account-service + + + diff --git a/labx-17/pom.xml b/labx-17/pom.xml new file mode 100644 index 00000000..5619bead --- /dev/null +++ b/labx-17/pom.xml @@ -0,0 +1,19 @@ + + + + labs-parent + cn.iocoder.springboot.labs + 1.0-SNAPSHOT + + 4.0.0 + + labx-17 + pom + + labx-17-sca-seata-at-dubbo-demo + + + + diff --git a/pom.xml b/pom.xml index 8fead415..c377bcd4 100644 --- a/pom.xml +++ b/pom.xml @@ -81,6 +81,7 @@ labx-16 lab-52 lab-53 + labx-17