有关seata的安装,请参看博客:https://blog.csdn.net/lianghecai52171314/article/details/127330916
业务需求:下单—减库存—扣钱—改订单状态当用户下单时,会在订单服务中创建一个订单,然后通过远程调用库存服务来扣减下单商品的库存;再通过远程调用账户服务来扣减用户账户里面的余额;最后订单服务中修改订单状态。
需要涉及到三个模块:
模块名数据库名portContext-pathApplication-namefafu-accountseata_account3001fafuFafu-account-3001fafu-storageseata_storage4001fafuFafu-storage-4001fafu-orderseata_order5001fafuFafu-order-5001可以看出:该操作需要跨域三个数据库,有两次远程调用,需要用到分布式事务技术。
数据库准备 创建seata_order数据库,然后在其中创建表tb_order:CREATE TABLE `tb_order` (
`id` bigint UNSIGNED NOT NULL COMMENT '订单编号',
`user_id` bigint UNSIGNED NULL DEFAULT NULL COMMENT '用户编号',
`sku_id` bigint UNSIGNED NULL DEFAULT NULL COMMENT '商品编号',
`count` int UNSIGNED NULL DEFAULT NULL COMMENT '数量',
`money` decimal(10, 3) UNSIGNED NULL DEFAULT NULL COMMENT '金额',
`state` int UNSIGNED NULL DEFAULT NULL COMMENT '状态',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
上面表的设计只是模拟性质的,大概对应的是拼多多的业务,一个订单中只能购买1种商品,但这种商品可以购买多个。
创建seata_storage数据库,然后在其中创建表tb_storage
CREATE TABLE `tb_storage` (
`id` bigint UNSIGNED NOT NULL COMMENT '编号',
`sku_id` bigint UNSIGNED NULL DEFAULT NULL COMMENT '商品编号',
`total` int UNSIGNED NULL DEFAULT NULL COMMENT '总库存',
`used` int UNSIGNED NULL DEFAULT NULL COMMENT '已用库存',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
创建seata_account数据库,然后在其中创建表tb_account:
CREATE TABLE `tb_account` (
`id` bigint UNSIGNED NOT NULL COMMENT '编号',
`total` decimal(11, 3) UNSIGNED NULL DEFAULT NULL COMMENT '总额度',
`used` decimal(11, 3) UNSIGNED NULL DEFAULT NULL COMMENT '已用额度',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
依次在三个数据库创建undo_log 表,用于保存需要回滚的数据:
CREATE TABLE `undo_log` (
`id` bigint NOT NULL AUTO_INCREMENT,
`branch_id` bigint NOT NULL,
`xid` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
`context` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
`rollback_info` longblob NOT NULL,
`log_status` int NOT NULL,
`log_created` datetime NOT NULL,
`log_modified` datetime NOT NULL,
`ext` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE,
UNIQUE INDEX `ux_undo_log`(`xid` ASC, `branch_id` ASC) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
注:每个服务对应的业务数据库都需要创建这个日志表。
项目共同部分 Nacos中在Nacos添加给客户端加载使用的配置seata-client-demo.yml:
- Data Id:seata-client-demo.yml
- Group:SEATA_GROUP
注意:上面配置中的group和nampespace都是在Nacos中创建命名空间时创建的。 上面配置的具体内容如下:
# seata配置
seata:
enabled: true
application-id: seata-cilent-deme
# Seata 事务组编号,此处需于 seata 相同
tx-service-group: default-tx-group
config:
type: nacos
nacos:
# nacos ip地址
server-addr: 127.0.0.1:8848
group: SEATA_GROUP
namespace: 99970600-6f67-43fd-a2a2-4e9795947bf4
data-id: seata-server.properties
registry:
type: nacos
nacos:
application: seata-server
# nacos ip地址
server-addr: 127.0.0.1:8848
group: SEATA_GROUP
namespace: 99970600-6f67-43fd-a2a2-4e9795947bf4
依赖
org.projectlombok
lombok
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-actuator
org.springframework.boot
spring-boot-devtools
runtime
true
org.springframework.boot
spring-boot-starter-test
test
mysql
mysql-connector-java
com.alibaba
druid-spring-boot-starter
com.baomidou
mybatis-plus-boot-starter
org.springframework.cloud
spring-cloud-starter-openfeign
org.springframework.cloud
spring-cloud-starter-loadbalancer
com.alibaba.cloud
spring-cloud-starter-alibaba-nacos-discovery
com.alibaba.cloud
spring-cloud-starter-alibaba-sentinel
com.alibaba.csp
sentinel-datasource-nacos
io.seata
seata-spring-boot-starter
1.5.2
com.alibaba.cloud
spring-cloud-starter-alibaba-seata
io.seata
seata-spring-boot-starter
Result
@Getter
@ToString
public class Result {
/**
* 请求响应状态码
*/
private int code;
/**
* 请求结果描述信息
*/
private String msg;
/**
* 请求结果数据
*/
private T data;
public Result setCode(int code) {
this.code = code;
return this;
}
public Result setMsg(String msg) {
this.msg = msg;
return this;
}
public Result setData(T data) {
this.data = data;
return this;
}
public static void main(String[] args) {
Result result = new Result().addData("a", "aaa", "b", 123, "c", new Date());
System.out.println(result);
}
/**
* 将key-value形式的成对出现的参数转换为JSON
*
* @param objs
* @return
*/
public Result addData(Object... objs) {
if (objs.length % 2 != 0) {
throw new RuntimeException("参数个数不对");
}
for (int i = 0; i
关注
打赏
最近更新
- 深拷贝和浅拷贝的区别(重点)
- 【Vue】走进Vue框架世界
- 【云服务器】项目部署—搭建网站—vue电商后台管理系统
- 【React介绍】 一文带你深入React
- 【React】React组件实例的三大属性之state,props,refs(你学废了吗)
- 【脚手架VueCLI】从零开始,创建一个VUE项目
- 【React】深入理解React组件生命周期----图文详解(含代码)
- 【React】DOM的Diffing算法是什么?以及DOM中key的作用----经典面试题
- 【React】1_使用React脚手架创建项目步骤--------详解(含项目结构说明)
- 【React】2_如何使用react脚手架写一个简单的页面?