需求背景:
模拟下单场景:首先去在自己的本地创建一条下单记录,同时,还要去调用库存服务,执行减库存操作。
这里演示一个客户下订单的流程服务来为小伙伴们进一步了解一下分布式事务到底如何使用?
首先,我会把系统模块中,开发订单需求;然后,再创建一个库存的子模块,最后,客户端发起订单请求,系统模块接收到请求后,在本地数据库中创建一个。
文章目录
- 一、数据库部分
- 1. 订单表创建
- 2. 库存数据库创建
- 3. 库存表结构初始化
- 4. 添加依赖
- 二、订单微服务代码部分
- 2.1. 创建实体类
- 2.2. 创建接口类
- 2.3. 调整控制层逻辑
- 2.4. 修改配置文件
- 三、库存微服务代码部分
- 3.1. 创建实体类
- 3.2. 接口库存Dao
- 3.3. 容错代码
- 3.4. 控制层逻辑调整
- 3.5. 配置文件修改
- 3.6. 初始化库存
- 3.7. 容错代码简述
- 四、测试验证
- 4.1. 启动服务
- 4.2. 发起第一轮请求
- 4.3. 抛出异常
- 4.4. 异常信息监控
- 4.5. 流程梳理
- 4.6. 数据库验证
- 4.7. 发起第二轮请求
- 4.8. 发起第三轮请求
- 4.9. 数据库数据验证
- 4.10. 发起第四轮请求
- 4.11. 数据库验证
一、数据库部分
1. 订单表创建
在系统模块连接的,ry-cloud数据库中创建一张订单表 和 AT模式seata需要用到的undolog表,其中undo_log表,在前面已经创建过了
create table order_tb
(id int auto_incrementprimary key,user_id int not null,product_id int not null
);CREATE TABLE `undo_log` (`branch_id` bigint(20) NOT NULL COMMENT 'branch transaction id',`xid` varchar(100) NOT NULL COMMENT 'global transaction id',`context` varchar(128) NOT NULL COMMENT 'undo_log context,such as serialization',`rollback_info` longblob NOT NULL COMMENT 'rollback info',`log_status` int(11) NOT NULL COMMENT '0:normal status,1:defense status',`log_created` datetime(6) NOT NULL COMMENT 'create datetime',`log_modified` datetime(6) NOT NULL COMMENT 'modify datetime',UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='AT transaction mode undo table';
2. 库存数据库创建
创建ry-stock
数据库
3. 库存表结构初始化
```bash
create table stock
(id int auto_incrementprimary key,count int not null,product_id int not null
);CREATE TABLE `undo_log` (`branch_id` bigint(20) NOT NULL COMMENT 'branch transaction id',`xid` varchar(100) NOT NULL COMMENT 'global transaction id',`context` varchar(128) NOT NULL COMMENT 'undo_log context,such as serialization',`rollback_info` longblob NOT NULL COMMENT 'rollback info',`log_status` int(11) NOT NULL COMMENT '0:normal status,1:defense status',`log_created` datetime(6) NOT NULL COMMENT 'create datetime',`log_modified` datetime(6) NOT NULL COMMENT 'modify datetime',UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='AT transaction mode undo table';
4. 添加依赖
系统模块
<!--Lombok引入--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency>
二、订单微服务代码部分
我们对现在的order-serv订单服务基础上调整
2.1. 创建实体类
2.2. 创建接口类
2.3. 调整控制层逻辑
2.4. 修改配置文件
三、库存微服务代码部分
3.1. 创建实体类
3.2. 接口库存Dao
3.3. 容错代码
3.4. 控制层逻辑调整
3.5. 配置文件修改
3.6. 初始化库存
3.7. 容错代码简述
四、测试验证
4.1. 启动服务
4.2. 发起第一轮请求
4.3. 抛出异常
4.4. 异常信息监控
4.5. 流程梳理
4.6. 数据库验证
4.7. 发起第二轮请求
4.8. 发起第三轮请求
4.9. 数据库数据验证
4.10. 发起第四轮请求
4.11. 数据库验证
改之前配置
# spring配置
spring: redis:host: localhostport: 6379password: 123456datasource:druid:stat-view-servlet:enabled: trueloginUsername: adminloginPassword: 123456dynamic:druid:initial-size: 5min-idle: 5maxActive: 20maxWait: 60000timeBetweenEvictionRunsMillis: 60000minEvictableIdleTimeMillis: 300000validationQuery: SELECT 1 FROM DUALtestWhileIdle: truetestOnBorrow: falsetestOnReturn: falsepoolPreparedStatements: truemaxPoolPreparedStatementPerConnectionSize: 20filters: stat,slf4jconnectionProperties: druid.stat.mergeSql\=true;druid.stat.slowSqlMillis\=5000datasource:# 主库数据源master:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/ry-cloud?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8username: rootpassword: 123456# 从库数据源# slave:# username: # password: # url: # driver-class-name: # seata: true # 开启seata代理,开启后默认每个数据源都代理,如果某个不需要代理可单独关闭# seata配置
seata:# 默认关闭,如需启用spring.datasource.dynami.seata需要同时开启enabled: false# Seata 应用编号,默认为 ${spring.application.name}application-id: ${spring.application.name}# Seata 事务组编号,用于 TC 集群名tx-service-group: ${spring.application.name}-group# 关闭自动代理enable-auto-data-source-proxy: false# 服务配置项service:# 虚拟组和分组的映射vgroup-mapping:ruoyi-system-group: defaultconfig:type: nacosnacos:serverAddr: 127.0.0.1:8848group: SEATA_GROUPnamespace:registry:type: nacosnacos:application: seata-serverserver-addr: 127.0.0.1:8848namespace:# mybatis配置
mybatis:# 搜索指定包别名typeAliasesPackage: com.ruoyi.system# 配置mapper的扫描,找到所有的mapper.xml映射文件mapperLocations: classpath:mapper/**/*.xml# swagger配置
swagger:title: 系统模块接口文档license: Powered By ruoyilicenseUrl: https://ruoyi.vip
调整之后配置
# spring配置
spring: redis:host: localhostport: 6379password: 123456datasource:druid:stat-view-servlet:enabled: trueloginUsername: adminloginPassword: 123456dynamic:druid:initial-size: 5min-idle: 5maxActive: 20maxWait: 60000timeBetweenEvictionRunsMillis: 60000minEvictableIdleTimeMillis: 300000validationQuery: SELECT 1 FROM DUALtestWhileIdle: truetestOnBorrow: falsetestOnReturn: falsepoolPreparedStatements: truemaxPoolPreparedStatementPerConnectionSize: 20filters: stat,slf4jconnectionProperties: druid.stat.mergeSql\=true;druid.stat.slowSqlMillis\=5000datasource:# 主库数据源master:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/ry-cloud?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8username: rootpassword: 123456# 从库数据源# slave:# username: # password: # url: # driver-class-name: seata: true # 开启seata代理,开启后默认每个数据源都代理,如果某个不需要代理可单独关闭# seata配置
seata:# 默认关闭,如需启用spring.datasource.dynami.seata需要同时开启enabled: true# Seata 应用编号,默认为 ${spring.application.name}application-id: ${spring.application.name}# Seata 事务组编号,用于 TC 集群名tx-service-group: order-service# 关闭自动代理enable-auto-data-source-proxy: false# 服务配置项service:# 虚拟组和分组的映射vgroup-mapping:ruoyi-system-group: defaultconfig:type: nacosnacos:serverAddr: 127.0.0.1:8848group: SEATA_GROUPnamespace: publicuserName: "nacos"password: "nacos"registry:type: nacosnacos:application: seata-serverserver-addr: 127.0.0.1:8848group: SEATA_GROUPnamespace: publicuserName: "nacos"password: "nacos"# mybatis配置
mybatis:# 搜索指定包别名typeAliasesPackage: com.ruoyi.system# 配置mapper的扫描,找到所有的mapper.xml映射文件mapperLocations: classpath:mapper/**/*.xml# swagger配置
swagger:title: 系统模块接口文档license: Powered By ruoyilicenseUrl: https://ruoyi.vip