diff --git a/kernel-d-seata/README.md b/kernel-d-seata/README.md new file mode 100644 index 000000000..aff0b4426 --- /dev/null +++ b/kernel-d-seata/README.md @@ -0,0 +1 @@ +分布式事务Seata模块 diff --git a/kernel-d-seata/db/db.sql b/kernel-d-seata/db/db.sql new file mode 100644 index 000000000..dbd4925a7 --- /dev/null +++ b/kernel-d-seata/db/db.sql @@ -0,0 +1,111 @@ + +-- ---------------------------- +-- 订单库 +-- ---------------------------- +DROP DATABASE IF EXISTS `order`; +CREATE DATABASE IF NOT EXISTS `order` DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_general_ci; + +USE `order`; + +DROP TABLE IF EXISTS `order_info`; +CREATE TABLE `order_info` ( + `order_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '订单ID', + `product_id` bigint(20) NOT NULL COMMENT '商品ID', + `user_id` bigint(20) NOT NULL COMMENT '用户ID', + `prod_price` double(8, 2) NOT NULL COMMENT '商品单价', + `prod_number` int(11) NOT NULL COMMENT '商品数量', + `total_amount` double(10, 2) NOT NULL COMMENT '总价', + `pay_status` int(11) NOT NULL COMMENT '支付状态:1待支付,2已支付,3支付失败,已取消', + `create_user` bigint(20) NULL DEFAULT NULL COMMENT '创建者', + `create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间', + `update_user` bigint(20) NULL DEFAULT NULL COMMENT '更新者', + `update_time` datetime(0) NULL DEFAULT NULL COMMENT '更新时间', + `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备注', + PRIMARY KEY (`order_id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '订单表' ROW_FORMAT = Dynamic; + +DROP TABLE IF EXISTS `undo_log`; +CREATE TABLE `undo_log` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `branch_id` bigint(20) NOT NULL, + `xid` varchar(100) NOT NULL, + `context` varchar(128) NOT NULL, + `rollback_info` longblob NOT NULL, + `log_status` int(11) NOT NULL, + `log_created` datetime NOT NULL, + `log_modified` datetime NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`) +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT = 'seata事务记录'; + + +-- ---------------------------- +-- 仓储库 +-- ---------------------------- +DROP DATABASE IF EXISTS `storage`; +CREATE DATABASE IF NOT EXISTS `storage` DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_general_ci; + +USE `storage`; + +DROP TABLE IF EXISTS `product_info`; +CREATE TABLE `product_info` ( + `prod_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '商品ID', + `prod_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '商品名称', + `inventory` int(11) NOT NULL COMMENT '库存数量', + `prod_price` double(8, 2) NOT NULL COMMENT '商品单价', + `prod_status` int(11) NOT NULL COMMENT '上架状态:1上架,2下架', + `create_user` bigint(20) NULL DEFAULT NULL COMMENT '创建者', + `create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间', + `update_user` bigint(20) NULL DEFAULT NULL COMMENT '更新者', + `update_time` datetime(0) NULL DEFAULT NULL COMMENT '更新时间', + `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备注', + PRIMARY KEY (`prod_id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '商品表' ROW_FORMAT = Dynamic; + +DROP TABLE IF EXISTS `undo_log`; +CREATE TABLE `undo_log` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `branch_id` bigint(20) NOT NULL, + `xid` varchar(100) NOT NULL, + `context` varchar(128) NOT NULL, + `rollback_info` longblob NOT NULL, + `log_status` int(11) NOT NULL, + `log_created` datetime NOT NULL, + `log_modified` datetime NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`) +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT = 'seata事务记录'; + + +-- ---------------------------- +-- 用户库 +-- ---------------------------- +DROP DATABASE IF EXISTS `member`; +CREATE DATABASE IF NOT EXISTS `member` DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_general_ci; + +USE `member`; + +DROP TABLE IF EXISTS `member_wallet`; +CREATE TABLE `member_wallet` ( + `member_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '会员ID', + `member_balance` double(8, 2) DEFAULT '0.00' COMMENT '会员余额', + `member_integral` double(8, 2) DEFAULT '0.00' COMMENT '会员积分', + `create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间', + `update_user` bigint(20) NULL DEFAULT NULL COMMENT '更新者', + `update_time` datetime(0) NULL DEFAULT NULL COMMENT '更新时间', + PRIMARY KEY (`member_id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '用户钱包' ROW_FORMAT = Dynamic; + +DROP TABLE IF EXISTS `undo_log`; +CREATE TABLE `undo_log` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `branch_id` bigint(20) NOT NULL, + `xid` varchar(100) NOT NULL, + `context` varchar(128) NOT NULL, + `rollback_info` longblob NOT NULL, + `log_status` int(11) NOT NULL, + `log_created` datetime NOT NULL, + `log_modified` datetime NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`) +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT = 'seata事务记录'; diff --git a/kernel-d-seata/doc/seata使用手册.docx b/kernel-d-seata/doc/seata使用手册.docx new file mode 100644 index 000000000..9b129bfc0 Binary files /dev/null and b/kernel-d-seata/doc/seata使用手册.docx differ diff --git a/kernel-d-seata/pom.xml b/kernel-d-seata/pom.xml new file mode 100644 index 000000000..cf5b61599 --- /dev/null +++ b/kernel-d-seata/pom.xml @@ -0,0 +1,33 @@ + + + + cn.stylefeng.roses + roses-kernel + 7.0.2 + ../pom.xml + + 4.0.0 + + kernel-d-seata + + pom + + seata-demo-wallet-api + seata-demo-storage-api + seata-demo-order + + + + + + + cn.stylefeng.roses + kernel-a-rule + 7.0.2 + + + + + diff --git a/kernel-d-seata/seata-demo-order/pom.xml b/kernel-d-seata/seata-demo-order/pom.xml new file mode 100644 index 000000000..1c6503889 --- /dev/null +++ b/kernel-d-seata/seata-demo-order/pom.xml @@ -0,0 +1,41 @@ + + + + cn.stylefeng.roses + kernel-d-seata + 7.0.2 + ../pom.xml + + 4.0.0 + + seata-demo-order + + jar + + + org.springframework.cloud + spring-cloud-openfeign-core + 2.2.6.RELEASE + + + cn.stylefeng.roses + seata-demo-storage-api + 7.0.2 + compile + + + cn.stylefeng.roses + seata-demo-wallet-api + 7.0.2 + compile + + + io.seata + seata-all + 1.3.0 + + + + diff --git a/kernel-d-seata/seata-demo-order/src/main/java/cn/stylefeng/roses/kernel/seata/order/consumer/StorageConsumer.java b/kernel-d-seata/seata-demo-order/src/main/java/cn/stylefeng/roses/kernel/seata/order/consumer/StorageConsumer.java new file mode 100644 index 000000000..acf94aa9f --- /dev/null +++ b/kernel-d-seata/seata-demo-order/src/main/java/cn/stylefeng/roses/kernel/seata/order/consumer/StorageConsumer.java @@ -0,0 +1,13 @@ +package cn.stylefeng.roses.kernel.seata.order.consumer; + +import cn.stylefeng.roses.kernel.seata.api.StorageApi; +import org.springframework.cloud.openfeign.FeignClient; + +/** + * 仓储api + * @author wangyl + * @Date 2021-04-10 9:25:13 + */ +@FeignClient(name = "seata-demo-storage") +public interface StorageConsumer extends StorageApi { +} diff --git a/kernel-d-seata/seata-demo-order/src/main/java/cn/stylefeng/roses/kernel/seata/order/consumer/WalletConsumer.java b/kernel-d-seata/seata-demo-order/src/main/java/cn/stylefeng/roses/kernel/seata/order/consumer/WalletConsumer.java new file mode 100644 index 000000000..09031948d --- /dev/null +++ b/kernel-d-seata/seata-demo-order/src/main/java/cn/stylefeng/roses/kernel/seata/order/consumer/WalletConsumer.java @@ -0,0 +1,13 @@ +package cn.stylefeng.roses.kernel.seata.order.consumer; + +import cn.stylefeng.roses.kernel.seata.wallet.api.WalletApi; +import org.springframework.cloud.openfeign.FeignClient; + +/** + * 用户钱包api + * @author wangyl + * @Date 2021-04-10 9:25:13 + */ +@FeignClient(name = "seata-demo-wallet") +public interface WalletConsumer extends WalletApi { +} diff --git a/kernel-d-seata/seata-demo-order/src/main/java/cn/stylefeng/roses/kernel/seata/order/controller/OrderController.java b/kernel-d-seata/seata-demo-order/src/main/java/cn/stylefeng/roses/kernel/seata/order/controller/OrderController.java new file mode 100644 index 000000000..00059c054 --- /dev/null +++ b/kernel-d-seata/seata-demo-order/src/main/java/cn/stylefeng/roses/kernel/seata/order/controller/OrderController.java @@ -0,0 +1,26 @@ +package cn.stylefeng.roses.kernel.seata.order.controller; + +import cn.stylefeng.roses.kernel.seata.order.entity.Order; +import cn.stylefeng.roses.kernel.seata.order.service.OrderService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; + +/** + * 订单接口 + * @author wangyl + * @Date 2021-04-10 9:25:13 + */ +public class OrderController { + + @Autowired + OrderService orderService; + + /** + * 创建订单 + */ + @GetMapping("/create") + Order create(String userId, String commodityCode, int orderCount){ + return orderService.create(userId,commodityCode,orderCount); + } + +} diff --git a/kernel-d-seata/seata-demo-order/src/main/java/cn/stylefeng/roses/kernel/seata/order/entity/Order.java b/kernel-d-seata/seata-demo-order/src/main/java/cn/stylefeng/roses/kernel/seata/order/entity/Order.java new file mode 100644 index 000000000..36ecb95cf --- /dev/null +++ b/kernel-d-seata/seata-demo-order/src/main/java/cn/stylefeng/roses/kernel/seata/order/entity/Order.java @@ -0,0 +1,116 @@ +package cn.stylefeng.roses.kernel.seata.order.entity; + +import java.io.Serializable; +import java.util.Date; + +public class Order implements Serializable { + + private Long orderId; + private Long productId; + private Long userId; + private Integer prodPrice; + private Integer prodNumber; + private Integer totalAmount; + private Integer payStatus; + private Long createUser; + private Date createTime; + private Long updateUser; + private Date updateTime; + private String remark; + + public Long getOrderId() { + return orderId; + } + + public void setOrderId(Long orderId) { + this.orderId = orderId; + } + + public Long getProductId() { + return productId; + } + + public void setProductId(Long productId) { + this.productId = productId; + } + + public Long getUserId() { + return userId; + } + + public void setUserId(Long userId) { + this.userId = userId; + } + + public Integer getProdPrice() { + return prodPrice; + } + + public void setProdPrice(Integer prodPrice) { + this.prodPrice = prodPrice; + } + + public Integer getProdNumber() { + return prodNumber; + } + + public void setProdNumber(Integer prodNumber) { + this.prodNumber = prodNumber; + } + + public Integer getTotalAmount() { + return totalAmount; + } + + public void setTotalAmount(Integer totalAmount) { + this.totalAmount = totalAmount; + } + + public Integer getPayStatus() { + return payStatus; + } + + public void setPayStatus(Integer payStatus) { + this.payStatus = payStatus; + } + + public Long getCreateUser() { + return createUser; + } + + public void setCreateUser(Long createUser) { + this.createUser = createUser; + } + + public Date getCreateTime() { + return createTime; + } + + public void setCreateTime(Date createTime) { + this.createTime = createTime; + } + + public Long getUpdateUser() { + return updateUser; + } + + public void setUpdateUser(Long updateUser) { + this.updateUser = updateUser; + } + + public Date getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(Date updateTime) { + this.updateTime = updateTime; + } + + public String getRemark() { + return remark; + } + + public void setRemark(String remark) { + this.remark = remark; + } +} diff --git a/kernel-d-seata/seata-demo-order/src/main/java/cn/stylefeng/roses/kernel/seata/order/mapper/OrderMapper.java b/kernel-d-seata/seata-demo-order/src/main/java/cn/stylefeng/roses/kernel/seata/order/mapper/OrderMapper.java new file mode 100644 index 000000000..edd600268 --- /dev/null +++ b/kernel-d-seata/seata-demo-order/src/main/java/cn/stylefeng/roses/kernel/seata/order/mapper/OrderMapper.java @@ -0,0 +1,16 @@ +package cn.stylefeng.roses.kernel.seata.order.mapper; + +import cn.stylefeng.roses.kernel.seata.order.entity.Order; + +/** + * 数据层 + * + * @author wangyl + */ +public interface OrderMapper { + + void insertOrder(Order order); + + Order selectById(Long orderId); + +} diff --git a/kernel-d-seata/seata-demo-order/src/main/java/cn/stylefeng/roses/kernel/seata/order/mapper/mapping/OrderMapper.xml b/kernel-d-seata/seata-demo-order/src/main/java/cn/stylefeng/roses/kernel/seata/order/mapper/mapping/OrderMapper.xml new file mode 100644 index 000000000..192054e36 --- /dev/null +++ b/kernel-d-seata/seata-demo-order/src/main/java/cn/stylefeng/roses/kernel/seata/order/mapper/mapping/OrderMapper.xml @@ -0,0 +1,38 @@ + + + + + + insert into order( + product_id, + user_id, + prod_price, + prod_number, + total_amount, + pay_status, + create_user, + create_time + update_user, + update_time, + remark, + )values( + #{productId}, + #{userId}, + #{prodPrice}, + #{prodNumber}, + #{totalAmount}, + #{payStatus}, + #{createUser}, + #{createTime} + #{updateUser}, + #{updateTime}, + #{remark}, + ) + + + + + diff --git a/kernel-d-seata/seata-demo-order/src/main/java/cn/stylefeng/roses/kernel/seata/order/service/OrderService.java b/kernel-d-seata/seata-demo-order/src/main/java/cn/stylefeng/roses/kernel/seata/order/service/OrderService.java new file mode 100644 index 000000000..78d2f299c --- /dev/null +++ b/kernel-d-seata/seata-demo-order/src/main/java/cn/stylefeng/roses/kernel/seata/order/service/OrderService.java @@ -0,0 +1,9 @@ +package cn.stylefeng.roses.kernel.seata.order.service; + +import cn.stylefeng.roses.kernel.seata.order.entity.Order; + +public interface OrderService { + + Order create(String userId, String commodityCode, int orderCount); + +} diff --git a/kernel-d-seata/seata-demo-order/src/main/java/cn/stylefeng/roses/kernel/seata/order/service/impl/OrderServiceImpl.java b/kernel-d-seata/seata-demo-order/src/main/java/cn/stylefeng/roses/kernel/seata/order/service/impl/OrderServiceImpl.java new file mode 100644 index 000000000..90ef8510e --- /dev/null +++ b/kernel-d-seata/seata-demo-order/src/main/java/cn/stylefeng/roses/kernel/seata/order/service/impl/OrderServiceImpl.java @@ -0,0 +1,41 @@ +package cn.stylefeng.roses.kernel.seata.order.service.impl; + +import cn.stylefeng.roses.kernel.seata.order.consumer.StorageConsumer; +import cn.stylefeng.roses.kernel.seata.order.consumer.WalletConsumer; +import cn.stylefeng.roses.kernel.seata.order.entity.Order; +import cn.stylefeng.roses.kernel.seata.order.mapper.OrderMapper; +import cn.stylefeng.roses.kernel.seata.order.service.OrderService; +import io.seata.spring.annotation.GlobalTransactional; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class OrderServiceImpl implements OrderService { + + @Autowired + private StorageConsumer storageConsumer; + @Autowired + private WalletConsumer walletConsumer; + @Autowired + private OrderMapper orderMapper; + + /** + * 分布式事务跨库操作,起始位置,使用@GlobalTransactional注解修饰 + * @param userId + * @param commodityCode + * @param orderCount + * @return + */ + @GlobalTransactional(rollbackFor = Exception.class) + @Override + public Order create(String userId, String commodityCode, int orderCount) { + Order order = new Order(); + //保存订单 + orderMapper.insertOrder(order); + //扣减商品库存 + storageConsumer.deduct(commodityCode,orderCount); + //扣用户钱 + walletConsumer.debit(userId,order.getTotalAmount()); + return order; + } +} diff --git a/kernel-d-seata/seata-demo-storage-api/pom.xml b/kernel-d-seata/seata-demo-storage-api/pom.xml new file mode 100644 index 000000000..8bfb389a4 --- /dev/null +++ b/kernel-d-seata/seata-demo-storage-api/pom.xml @@ -0,0 +1,17 @@ + + + + cn.stylefeng.roses + kernel-d-seata + 7.0.2 + ../pom.xml + + 4.0.0 + + seata-demo-storage-api + + jar + + diff --git a/kernel-d-seata/seata-demo-storage-api/src/main/java/cn/stylefeng/roses/kernel/seata/api/StorageApi.java b/kernel-d-seata/seata-demo-storage-api/src/main/java/cn/stylefeng/roses/kernel/seata/api/StorageApi.java new file mode 100644 index 000000000..f45a7b30a --- /dev/null +++ b/kernel-d-seata/seata-demo-storage-api/src/main/java/cn/stylefeng/roses/kernel/seata/api/StorageApi.java @@ -0,0 +1,16 @@ +package cn.stylefeng.roses.kernel.seata.api; + +/** + * 仓储api + * + * @author wangyl + * @date 2021-04-11 9:52:31 + */ +public interface StorageApi { + + /** + * 扣除存储数量 + */ + void deduct(String commodityCode, int count); + +} diff --git a/kernel-d-seata/seata-demo-wallet-api/pom.xml b/kernel-d-seata/seata-demo-wallet-api/pom.xml new file mode 100644 index 000000000..6bae3c51b --- /dev/null +++ b/kernel-d-seata/seata-demo-wallet-api/pom.xml @@ -0,0 +1,17 @@ + + + + cn.stylefeng.roses + kernel-d-seata + 7.0.2 + ../pom.xml + + 4.0.0 + + seata-demo-wallet-api + + jar + + diff --git a/kernel-d-seata/seata-demo-wallet-api/src/main/java/cn/stylefeng/roses/kernel/seata/wallet/api/WalletApi.java b/kernel-d-seata/seata-demo-wallet-api/src/main/java/cn/stylefeng/roses/kernel/seata/wallet/api/WalletApi.java new file mode 100644 index 000000000..c7caa0ae7 --- /dev/null +++ b/kernel-d-seata/seata-demo-wallet-api/src/main/java/cn/stylefeng/roses/kernel/seata/wallet/api/WalletApi.java @@ -0,0 +1,16 @@ +package cn.stylefeng.roses.kernel.seata.wallet.api; + +/** + * 用户钱包api + * + * @author wangyl + * @date 2021-04-10 8:56:48 + */ +public interface WalletApi { + + /** + * 从用户账户中借出 + */ + void debit(String userId, int money); + +} diff --git a/pom.xml b/pom.xml index 6004ce866..2f053ec18 100644 --- a/pom.xml +++ b/pom.xml @@ -94,6 +94,9 @@ kernel-s-system + + kernel-d-seata +