springcloud第三讲
创始人
2025-05-31 07:16:50
0

目录

三、springcloud03

3.1 普通事务

3.2 演示事务

3.2.1、建库

3.2.2 创建父工程

3.2.3 编写公共微服务

3.2.4 编写账户微服务

3.2.5 编写库存微服务

3.2.6 编写订单微服务

3.2.7 测试

3.3 分布式事务

3.4 介绍seata

3.5 搭建seata服务器

3.5.1 解决集群共享数据

3.5.2 seata连接nacos

3.6 配置微服务客户端

3.6.1 创建数据库

3.6.2 修改微服务代码

三、springcloud03

3.1 普通事务

普通事务

1、ACID事务的特点:原子性、一致性、隔离性、持久性

2、事务并发带来的问题:脏读、幻读、不可重复读、丢失修改

3、我们可以使用事务的隔离级别来解决

读未提交、读已提交、可重复读、串行化

事务(TRANSACTION)是作为单个逻辑工作单元执行的一系列SQL操作,这些操作作为一个整体一起向系统提交,要么都执行、要么都不执行。

 

3.2 演示事务

3.2.1、建库

创建三个数据库,每个数据库一张表,表名和库名一致即可,这里使用的是mysql5.7的建表语句,没有collect

/*Navicat Premium Data Transfer
​Source Server         : localhost_3306Source Server Type    : MySQLSource Server Version : 80011Source Host           : localhost:3306Source Schema         : seata_account
​Target Server Type    : MySQLTarget Server Version : 80011File Encoding         : 65001
​Date: 28/11/2022 15:28:32
*/
​
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
​
-- ----------------------------
-- Table structure for t_account
-- ----------------------------
DROP TABLE IF EXISTS `t_account`;
CREATE TABLE `t_account`  (`id` int(11) NOT NULL AUTO_INCREMENT,`user_id` int(11) NULL DEFAULT NULL,`total` int(11) NULL DEFAULT NULL,`used` int(11) NULL DEFAULT NULL,`residue` int(11) NULL DEFAULT NULL,PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4;
​
-- ----------------------------
-- Records of t_account
-- ----------------------------
INSERT INTO `t_account` VALUES (1, 1, 1000, 100, 900);
​
SET FOREIGN_KEY_CHECKS = 1;
/*Navicat Premium Data Transfer
​Source Server         : localhost_3306Source Server Type    : MySQLSource Server Version : 80011Source Host           : localhost:3306Source Schema         : seata_order
​Target Server Type    : MySQLTarget Server Version : 80011File Encoding         : 65001
​Date: 28/11/2022 15:28:38
*/
​
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
​
-- ----------------------------
-- Table structure for t_order
-- ----------------------------
DROP TABLE IF EXISTS `t_order`;
CREATE TABLE `t_order`  (`id` int(11) NOT NULL AUTO_INCREMENT,`user_id` int(11) NULL DEFAULT NULL,`product_id` int(11) NULL DEFAULT NULL,`count` int(11) NULL DEFAULT NULL,`money` bigint(20) NULL DEFAULT NULL,`status` int(11) NULL DEFAULT 0 COMMENT '0 未支付  1 已支付',PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 46 CHARACTER SET = utf8mb4;
​
-- ----------------------------
-- Records of t_order
-- ----------------------------
INSERT INTO `t_order` VALUES (47, 1, 1, 5, 100, 1);
​
SET FOREIGN_KEY_CHECKS = 1;
/*Navicat Premium Data Transfer
​Source Server         : localhost_3306Source Server Type    : MySQLSource Server Version : 80011Source Host           : localhost:3306Source Schema         : seata_storage
​Target Server Type    : MySQLTarget Server Version : 80011File Encoding         : 65001
​Date: 28/11/2022 15:28:45
*/
​
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
​
-- ----------------------------
-- Table structure for t_storage
-- ----------------------------
DROP TABLE IF EXISTS `t_storage`;
CREATE TABLE `t_storage`  (`id` int(11) NOT NULL AUTO_INCREMENT,`product_id` int(11) NULL DEFAULT NULL,`total` int(11) NULL DEFAULT NULL COMMENT '总量',`used` int(11) NULL DEFAULT NULL COMMENT '已经使用的数量',`residue` int(11) NULL DEFAULT NULL COMMENT '剩余的数据量',PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8;
​
-- ----------------------------
-- Records of t_storage
-- ----------------------------
INSERT INTO `t_storage` VALUES (1, 1, 100, 0, 100);
​
SET FOREIGN_KEY_CHECKS = 1;

3.2.2 创建父工程

删掉src,只保留pom文件即可


4.0.0com.ykqseata_parent1.0-SNAPSHOTseata-commonseata-accountseata-orderseata-storagepomorg.springframework.bootspring-boot-starter-parent2.3.12.RELEASE1.8UTF-8UTF-8Hoxton.SR82.2.3.RELEASEorg.springframework.cloudspring-cloud-dependencies${spring-cloud.version}pomimportcom.alibaba.cloudspring-cloud-alibaba-dependencies${spring-cloud-alibaba.version}pomimport

3.2.3 编写公共微服务

1、pom文件


seata_parentcom.ykq1.0-SNAPSHOT4.0.0seata-commonorg.projectlomboklombok

2、实体类

package com.ykq.entity;
​
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
//账户
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Account {private int id;private int userId;private int total;private int used;private int residue;
}
package com.ykq.entity;
​
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
//统一返回结果
@Data
@AllArgsConstructor
@NoArgsConstructor
public class CommonResult {
​private Integer code;private String message;private T data;public CommonResult(Integer code, String message) {this(code, message, null);}
}
package com.ykq.entity;
​
import lombok.Data;
//订单
@Data
public class Order {private int id;private int userId;private int productId;private double money;private int count;private int status;
}
package com.ykq.entity;
​
import lombok.Data;
//库存
@Data
public class Storage {private int id;private int productId;private int total;private int used;//被用了多少个private int residue;//剩余的个数。
}

3.2.4 编写账户微服务

1、pom文件


seata_parentcom.ykq1.0-SNAPSHOT4.0.0seata-accountcom.ykqseata-common1.0-SNAPSHOTcom.alibaba.cloudspring-cloud-starter-alibaba-nacos-discoverycom.alibaba.cloudspring-cloud-starter-alibaba-nacos-configorg.springframework.bootspring-boot-starter-weborg.springframework.bootspring-boot-starter-jdbcorg.mybatis.spring.bootmybatis-spring-boot-starter2.1.3org.springframework.cloudspring-cloud-starter-openfeignorg.springframework.bootspring-boot-devtoolsruntimetruemysqlmysql-connector-javaruntimeorg.springframework.bootspring-boot-configuration-processortrueorg.projectlomboklomboktrueorg.springframework.bootspring-boot-starter-testtestorg.junit.vintagejunit-vintage-enginemysqlmysql-connector-java

2、配置文件

server:port: 8002
spring:# 数据源配置datasource:url: jdbc:mysql://localhost:3306/seata_account?serverTimezone=Asia/Shanghaidriver-class-name: com.mysql.cj.jdbc.Driverusername: rootpassword: 密码#配置服务名application:name: seata-account#nacos注册中心的地址cloud:nacos:discovery:server-addr: localhost:8848
mybatis:mapperLocations: classpath:mapper/*.xml
logging:level:com.ykq.dao: debug

3、mapper文件



update t_account set used = used + #{money},residue = residue - #{money}where user_id=#{userId}

4、mapper接口

package com.ykq.dao;
​
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
​
import java.math.BigDecimal;
​
@Mapper
public interface AccountDao {
​void decrease(@Param("userId") int userId, @Param("money") double money);
}

5、service接口

package com.ykq.service;
​
public interface AccountService {
​void decrease(int userId, double money);
}

6、service实现层

package com.ykq.service.impl;
​
import com.ykq.dao.AccountDao;
import com.ykq.service.AccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
​
@Service
public class AccountServiceImpl implements AccountService {@Autowiredprivate AccountDao accountDao;@Overridepublic void decrease(int userId, double money) {accountDao.decrease(userId,money);}
}

7、controller层

package com.ykq.controller;
​
import com.ykq.entity.CommonResult;
import com.ykq.service.AccountService;
import org.springframework.web.bind.annotation.*;
​
import javax.annotation.Resource;
import java.math.BigDecimal;
​
@RestController
@RequestMapping(value = "account")
public class AccountController {
​@Resourceprivate AccountService accountService;
​/*** 根据用户id扣余额* @param userId* @param money* @return*/@PostMapping("/increase/{userId}/{money}")public CommonResult increase(@PathVariable("userId")Integer userId,@PathVariable("money")double money) {accountService.decrease(userId, money);return new CommonResult(200,"账户余额扣减成功,哈哈哈");}
}

8、启动类

package com.ykq;
​
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
​
//1.3
@SpringBootApplication
@EnableDiscoveryClient
public class AccountApplication {
​public static void main(String[] args) {SpringApplication.run(AccountApplication.class, args);}
​
}

3.2.5 编写库存微服务

1、pom文件


seata_parentcom.ykq1.0-SNAPSHOT4.0.0seata-storagecom.ykqseata-common1.0-SNAPSHOTcom.alibaba.cloudspring-cloud-starter-alibaba-nacos-discoverycom.alibaba.cloudspring-cloud-starter-alibaba-nacos-configorg.springframework.bootspring-boot-starter-weborg.springframework.bootspring-boot-starter-jdbcorg.mybatis.spring.bootmybatis-spring-boot-starter2.1.3org.springframework.cloudspring-cloud-starter-openfeignorg.springframework.bootspring-boot-devtoolsruntimetruemysqlmysql-connector-javaruntimeorg.springframework.bootspring-boot-configuration-processortrueorg.projectlomboklomboktrueorg.springframework.bootspring-boot-starter-testtestorg.junit.vintagejunit-vintage-engine

和账户微服务的pom文件差不多,可以参考账户微服务

2、配置文件

server:port: 8003
spring:# 数据源配置datasource:url: jdbc:mysql://localhost:3306/seata_storage?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8driver-class-name: com.mysql.cj.jdbc.Driverusername: rootpassword: 密码application:name: seata-storagecloud:nacos:discovery:server-addr: localhost:8848alibaba:seata:tx-service-group: fsp_tx_group
mybatis:mapperLocations: classpath:mapper/*.xml
logging:level:com.ykq.dao: debug

3、mapper文件



update t_storage set used = used + #{count},residue = residue -#{count}where product_id = #{productId}

4、mapper接口

package com.ykq.dao;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
​
public interface StorageDao {void decrease(@Param("productId") int productId,@Param("count") Integer count);
}
​
​

5、service接口

package com.ykq.service;
​
public interface StorageService {void decrease(int productId, Integer count);
}

6、service实现类

package com.ykq.service.impl;
​
import com.ykq.dao.StorageDao;
import com.ykq.service.StorageService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
​
@Service
@Slf4j
public class StorageServiceImpl implements StorageService {@Autowiredprivate StorageDao storageDao;@Override@Transactionalpublic void decrease(int productId, Integer count) {log.info("库存扣减开始----");storageDao.decrease(productId,count);log.info("库存扣减结束----");}
}

7、controller层

package com.ykq.controller;
​
​
import com.ykq.entity.CommonResult;
import com.ykq.service.StorageService;
import org.springframework.web.bind.annotation.*;
​
import javax.annotation.Resource;
​
@RestController
@RequestMapping(value = "/storage")
public class StorageController {
​@Resourceprivate StorageService storageService;
​/*** 根据商品id扣减库存* @param productId* @param count* @return*/@PostMapping("/increase/{productId}/{count}")CommonResult increase(@PathVariable("productId") int productId, @PathVariable("count") int count){storageService.decrease(productId, count);return new CommonResult(200,"库存扣减成功,哈哈哈哈");}
}

8、启动类

package com.ykq;
​
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.transaction.annotation.EnableTransactionManagement;
​
@SpringBootApplication
@MapperScan("com.ykq.dao")
public class StorageApplication {
​public static void main(String[] args) {SpringApplication.run(StorageApplication.class, args);}
​
}
​

3.2.6 编写订单微服务

1、pom文件


seata_parentcom.ykq1.0-SNAPSHOT4.0.0seata-ordercom.ykqseata-common1.0-SNAPSHOT
​
​com.alibaba.cloudspring-cloud-starter-alibaba-nacos-discoverycom.alibaba.cloudspring-cloud-starter-alibaba-nacos-configorg.springframework.bootspring-boot-starter-weborg.springframework.bootspring-boot-starter-jdbcorg.mybatis.spring.bootmybatis-spring-boot-starter2.1.3org.springframework.cloudspring-cloud-starter-openfeignorg.springframework.bootspring-boot-devtoolsruntimetruemysqlmysql-connector-javaruntimeorg.springframework.bootspring-boot-configuration-processortrueorg.springframework.bootspring-boot-starter-testtestorg.junit.vintagejunit-vintage-engine

2、配置文件

server:port: 8001
​
spring:application:name: seata-order
# 数据源datasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/seata_order?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8username: rootpassword: 密码
# 把该服务注册到nacos上cloud:nacos:discovery:server-addr: localhost:8848
​
# 配置mybatis映射文件的路径
mybatis:mapperLocations: classpath:mapper/*.xml
# 显示mybatis执行的sql语句
logging:level:com.ykq.dao: debug

3、mapper文件




​
​insert into t_order(user_id,product_id,count,money,status)value (#{userId},#{productId},#{count},#{money},0)update t_order set status = 1where id = #{id} and status = 0

4、mapper接口

package com.ykq.dao;
​
import com.ykq.entity.Order;
​
public interface OrderDao {void saveOrder(Order order);
​void updateStatus(int id);
}

5、feign接口

因为要实现远程调用,所以这里要编写feign接口

package com.ykq.feign;
​
import com.ykq.entity.CommonResult;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
​
@FeignClient(value="seata-account")
public interface AccountFeign {
​@PostMapping("/account/increase/{userId}/{money}")public CommonResult increase(@PathVariable("userId")Integer userid, @PathVariable("money")double money);
}
package com.ykq.feign;
​
import com.ykq.entity.CommonResult;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
​
@FeignClient("seata-storage")
public interface StorageFeign {@PostMapping("/storage/increase/{productId}/{count}")CommonResult increase(@PathVariable("productId") int productId, @PathVariable("count") int count);
}

6、service接口

package com.ykq.service;
​
import com.ykq.entity.Order;
​
public interface OrderService {void saveOrder(Order order);
}
​

7、service实现类

package com.ykq.service.impl;
​
import com.ykq.dao.OrderDao;
import com.ykq.entity.Order;
import com.ykq.feign.AccountFeign;
import com.ykq.feign.StorageFeign;
import com.ykq.service.OrderService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
​
import javax.annotation.Resource;
​
@Service
@Slf4j
public class OrderServiceImpl implements OrderService {
​@Autowiredprivate OrderDao orderDao;
​@Autowiredprivate AccountFeign accountFeign;//表示调用的远程服务。
​@Autowiredprivate StorageFeign storageFeign;
​@Override@Transactionalpublic void saveOrder(Order order) {log.info("-------->开始创建新订单");orderDao.saveOrder(order);
​log.info("-------订单微服务开始调用账户,做扣减");accountFeign.increase(order.getUserId(),order.getMoney()); //当前的事务回滚只会回滚自己的数据log.info("-------订单微服务开始调用账户,做扣减end");log.info("--------订单微服务开始调用库存,做扣减");storageFeign.increase(order.getProductId(),order.getCount());log.info("-------订单微服务开始调用库存,做扣减end");
​
​log.info("-------修改订单状态");orderDao.updateStatus(order.getId());
​log.info("-------修改订单状态结束");
​log.info("--------下订单结束了,哈哈哈哈");}
​
}

8、controller层

package com.ykq.controller;
​
import com.ykq.entity.CommonResult;
import com.ykq.entity.Order;
import com.ykq.service.OrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
​
@RestController
@RequestMapping("order")
public class OrderController {@Autowiredprivate OrderService orderService;@GetMapping("addOrder")public CommonResult addOrder(Order order){try {orderService.saveOrder(order);return new CommonResult(2000, "下单成功");}catch (Exception e){return new CommonResult(5000, "下单失败");}}
}

9、启动类

package com.ykq;
​
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.transaction.annotation.EnableTransactionManagement;
​
@SpringBootApplication //排除原有的数据源的配置
@MapperScan("com.ykq.dao")
@EnableFeignClients //开启feign的注解
@EnableTransactionManagement
public class OrderApp {public static void main(String[] args) {SpringApplication.run(OrderApp.class,args);}
}

3.2.7 测试

代码编写完成,如果是粘贴的整个项目,配置文件红maven仓库也需要修改为自己的

3.2.7.1 成功测试

1、数据库初始状态

 

 

 

2、浏览器访问订单资源进行测试

请求为:http://localhost:8001/order/addOrder/?userId=1&productId=1&count=5&money=100

响应结果为:{"code":2000,"message":"下单成功","data":null}

 

3、响应成功后数据库

 

 

 

3.2.7.2 异常测试

人为的给订单微服务程序添加一个异常情况 【算术异常即可】比如:10/0

1、修改订单的service实现类

package com.ykq.service.impl;
​
import com.ykq.dao.OrderDao;
import com.ykq.entity.Order;
import com.ykq.feign.AccountFeign;
import com.ykq.feign.StorageFeign;
import com.ykq.service.OrderService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
​
import javax.annotation.Resource;
​
@Service
@Slf4j
public class OrderServiceImpl implements OrderService {
​@Autowiredprivate OrderDao orderDao;
​@Autowiredprivate AccountFeign accountFeign;//表示调用的远程服务。
​@Autowiredprivate StorageFeign storageFeign;
​@Override@Transactionalpublic void saveOrder(Order order) {log.info("-------->开始创建新订单");orderDao.saveOrder(order);
​log.info("-------订单微服务开始调用账户,做扣减");accountFeign.increase(order.getUserId(),order.getMoney()); //当前的事务回滚只会回滚自己的数据log.info("-------订单微服务开始调用账户,做扣减end");//添加异常int  c=10/0;log.info("--------订单微服务开始调用库存,做扣减");storageFeign.increase(order.getProductId(),order.getCount());log.info("-------订单微服务开始调用库存,做扣减end");
​
​log.info("-------修改订单状态");orderDao.updateStatus(order.getId());
​log.info("-------修改订单状态结束");
​log.info("--------下订单结束了,哈哈哈哈");}
}

注:这里异常添加在账户微服务之后,订单微服务之前

2、再次进行测试

请求:http://localhost:8001/order/addOrder/?userId=1&productId=1&count=5&money=100

请求结果:{"code":5000,"message":"下单失败","data":null}

3、查看数据库状态

 

 

 

3.3 分布式事务

分布式服务结构图如下:

 

因为每个事务都连接了自己的数据库,所以在进行事务操作时,

一个微服务(A)的成功,就会改变自己的数据库,即使其它微服务(B)失败,该微服务(A)也不会回滚自己的数据库

1. 借助rabbitMQ消息中间件
2. 可以自己编写代码完成分布式事务。
3. 借助于第三方分布式事务服务器。---阿里巴巴seata

3.4 介绍seata

seata官网地址:Seata部署指南

Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。Seata 将为用户提供了 AT[两次提交]、TCC、SAGA 和XA 事务模式,为用户打造一站式的分布式解决方案。

这次主要练习的就是AT事务模式

 

Seata的执行流程如下:

1、A服务【订单微服务】的TM[事务发起者]向TC[seata服务端]申请开启一个全局事务,TC就会创建一个全局事务并返回一个唯一的XID

2、A服务开始远程调用B服务【账户微服务】,此时XID会在微服务的调用链上传播

3、B服务的RM向TC注册分支事务,并将其纳入XID对应的全局事务的管辖

4、B服务执行分支事务,向数据库做操作

5、全局事务调用链处理完毕,TM根据有无异常向TC发起全局事务的提交或者回滚

6、TC协调其管辖之下的所有分支事务, 决定是否回滚

根据上面的测试进行举例来看,每一部分的角色如下

TM:事务的发起者--下单

RM: 连接数据库--微服务

TC:全局事务管理者--seata服务器

XID:全局事务id

3.5 搭建seata服务器

seata官网:Release v1.3.0 · seata/seata · GitHub

seata在1.3.0之后支持集群模式

解压文件

 

3.5.1 解决集群共享数据

1、修改conf/file.conf文件,更改数据保存的位置

 

1.1将源码压缩包解压后,找到其中script文件夹,将其复制到seata文件目录下

 

1.2 找到script\server\db目录下的mysql.sql文件,就是我们需要的三张表,将表添加到mysql中的seata数据库

 

1.3 因为在设置数据库时,我们选择的驱动是8的驱动,所以我们也需要有8的jar包,默认读取的是lib文件目录下的jar包,所以可以将seata/lib/jdbc/目录下的jar包粘贴到seata/lib目录下

3.5.2 seata连接nacos

当seata是一个集群时,微服务连接seata会无法选择seata,将seata接入到nacos,别的微服务就可以在nacos中拉取对应的seata服务

1、找到seata/conf/registry.conf文件进行修改

 

2、上传配置文件到nacos配置中心

找到seata\script\config-center目录下的config.txt文件,修改其中的配置,修改完之后,这些配置是需要放到配置中心的

 

注!!!!!!!!!!!!!!

url那一行,在最后多了一个双引号,一定要删掉

然后使用脚本将这些修改好的配置文件,传到nacos注册中心,脚本位置在seata\script\config-center\nacos\nacos-config.sh,如果安装了git,那么这里双击此脚本,会自动调用git的控制台,执行命令,将配置上传到配置中心

 

再执行时,也可以指定nacos的信息

 

3、启动搭建好的seata服务器,他会自动注册到nacos中

找到seata\bin目录下的seata-server.bat文件,双击即可执行,

如果需要指定端口号,可以进入到cmd中使用命令执行

seata-server.bat -Dserver.port=8989

 

3.6 配置微服务客户端

3.6.1 创建数据库

在每一个微服务的数据库中建一张日志表,表结构在seata\script\client\at\db目录下的mysql.sql中

 

3.6.2 修改微服务代码

这里先使用storage模块进行测试

1、添加依赖

        com.alibaba.cloudspring-cloud-starter-alibaba-seataio.seataseata-spring-boot-starterio.seataseata-spring-boot-starter1.3.0

当然这里版本是对应的,所以不需要修改版本

        com.alibaba.cloudspring-cloud-starter-alibaba-seata

2、编写配置文件这里改为properties文件

server.port=8003
#配置数据源
spring.datasource.url=jdbc:mysql://localhost:3306/seata_storage?serverTimezone=Asia/Shanghai
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=密码
#
spring.application.name=seata-storage
#注册中心地址
spring.cloud.nacos.discovery.server-addr=localhost:8848
#seata服务组的名字
spring.cloud.alibaba.seata.tx-service-group=guangzhou
seata.service.vgroup-mapping.guangzhou=default
#扫描mapper文件
mybatis.mapper-locations=classpath:mapper/*.xml
#日志扫描
logging.level.com.ykq.dao=debug
#seata注册类型
seata.registry.type=nacos
#注册中心的信息-----------------------------
#指定seata服务器所在的注册中心地址
seata.registry.nacos.server-addr=localhost:8848
#nacos的用户名和密码
seata.registry.nacos.username=nacos
seata.registry.nacos.password=nacos
#指定seata服务器在注册中心的组名,默认为SEATA_GROUP
seata.registry.nacos.group=SEATA_GROUP
#指定seata服务器在注册中心的服务名,默认为seata-server
seata.registry.nacos.application=seata-server
#注册中心的信息----------------------------------
#指定seata服务器所在的配置中心地址
seata.config.nacos.server-addr=localhost:8848
#nacos的用户名和密码
seata.config.nacos.username=nacos
seata.config.nacos.password=nacos
#指定seata服务器在配置中心的组名,默认为SEATA_GROUP
seata.config.nacos.group=SEATA_GROUP

3、运行项目进行测试

报错: no available service 'default' found, please make sure registry config correct

在配置文件中添加一行,这里的guangzhou就是自己命名的seata组名

seata.service.vgroup-mapping.guangzhou=default

再次运行就可以成功了,就代表着客户端也搭建完毕,将其他模块修改一下即可

4、修改发起者的代码 [订单微服务的service实现类]

package com.ykq.service.impl;
​
import com.ykq.dao.OrderDao;
import com.ykq.entity.Order;
import com.ykq.feign.AccountFeign;
import com.ykq.feign.StorageFeign;
import com.ykq.service.OrderService;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
​
import javax.annotation.Resource;
​
@Service
@Slf4j
public class OrderServiceImpl implements OrderService {
​@Autowiredprivate OrderDao orderDao;
​@Autowiredprivate AccountFeign accountFeign;//表示调用的远程服务。
​@Autowiredprivate StorageFeign storageFeign;
​@Override@GlobalTransactional   //使用这个注解进行分布式事务public void saveOrder(Order order) {log.info("-------->开始创建新订单");orderDao.saveOrder(order);
​log.info("-------订单微服务开始调用账户,做扣减");accountFeign.increase(order.getUserId(),order.getMoney()); //当前的事务回滚只会回滚自己的数据log.info("-------订单微服务开始调用账户,做扣减end");//添加异常// int  c=10/0;log.info("--------订单微服务开始调用库存,做扣减");storageFeign.increase(order.getProductId(),order.getCount());log.info("-------订单微服务开始调用库存,做扣减end");
​log.info("-------修改订单状态");orderDao.updateStatus(order.getId());
​log.info("-------修改订单状态结束");
​log.info("--------下订单结束了,哈哈哈哈");}
​
}

然后发起请求[数据库已经改为最初状态 拥有1000元,库存为100,订单数为0]

1、先验证正常情况

请求:http://localhost:8001/order/addOrder/?userId=1&productId=1&count=5&money=100

请求结果:{"code":2000,"message":"下单成功","data":null}

 

 

 

2、再测试异常情况

请求:http://localhost:8001/order/addOrder/?userId=1&productId=1&count=5&money=100

请求结果:

{"code":5000,"message":"下单失败","data":null}

 

 

其中一个微服务的事务失败,所有的事务都会回滚,

事务过程中,生成的信息存在日志表中,事务的信息存在seata数据库的三张表中,通过打断点可以看到中间的信息

相关内容

热门资讯

连亏五年,徽酒金种子掉队 (作者|周琦 编辑|张广凯) 昔日安徽名酒金种子酒,已连续五年陷入亏损泥淖。 一月初,公司发布2...
美元信用担忧持续强化导致黄金储... 1月28日上午收盘,三大指数涨跌不一,沪指震荡拉升,创业板指高开低走,一度跌超1%。沪深两市半日成交...
银行个人抵押经营贷利率普遍下探 本报记者 彭妍 据了解,多家银行个人抵押经营贷年化利率已下探至“2字头”区间,与此同时,经营贷的授信...
星辰天合提交港交所上市申请,今... 1月28日消息,北京星辰天合科技股份有限公司向港交所递交上市申请书,华泰国际为独家保荐人。 作为中国...
同星科技董事长32岁女儿被聘为... 瑞财经 赵盼盼1月26日,浙江同星科技股份有限公司(以下简称“同星科技”)发布关于董事会秘书辞职及聘...
中国与欧亚地区国家:基于欧亚开... 今天分享的是:中国与欧亚地区国家:基于欧亚开发银行相互投资监测的投资流分析-EDB 报告共计:35页...
中国人民银行与斯里兰卡中央银行... 记者1月28日从中国人民银行获悉,近日中国人民银行与斯里兰卡中央银行签署了在斯里兰卡建立人民币清算安...
原创 心... 心绞痛不是“老年人的病”,它正悄悄潜入中年人的身体。中国每年心梗死亡超30万,80%的患者因延误治疗...
券商开年新发超2300亿债券融... 2026年开年以来,券商发债融资延续火热态势并进一步提速。1月27日,国联民生证券发布公告称,公司及...
南方基金固收类夺冠!汇添富债基... 2025年固收类基金表现如何?哪些产品成绩亮眼?哪些表现拉垮?哪些基金为投资者赚取丰厚利润?谁家固收...
津药达仁堂集团董事长王磊荣膺“... 在2025中国经济高峰论坛颁奖盛典上,津药达仁堂集团党委书记、董事长王磊女士 被授予“2025年度经...
鸣鸣很忙港交所上市,开盘一度涨... 红星资本局1月28日消息,今日,湖南鸣鸣很忙商业连锁股份有限公司(以下简称“鸣鸣很忙”,01768....
鑫元鑫锐量化选股混合型发起式证... 1. 公告基本信息 ■ 2.基金募集情况 ■ ■ 注:1、本基金基金合同生效前的律师费、会计师费、信...
奥特曼亲口承认 GPT-5.2... ChatGPT 最近明显又有点焦虑。 一个月前还在拉红色警报应对 Gemini,现在又看到 Clau...
黄金,首次涨破5200美元!美... 1月28日亚太早盘,现货黄金涨势不减再创新高,盘中首次突破5200美元/盎司,本月累计上涨逾880美...
杨瀚森6分5板1助攻夏普31分... 【搜狐体育战报】北京时间1月28日NBA常规赛,主场作战的奇才以115-111击败开拓者,开拓者遭遇...
现货黄金刚刚涨破5200美元,... 北京时间1月28日早盘,现货黄金大幅拉涨,盘中首次站上5200美元,再创历史新高。截至发稿报5201...
因格智能完成数千万元融资 近日,全球全品类自动装卸领航者因格智能宣布完成数千万元的新一轮融资,由普华资本领投。本轮融资将重点用...
SEC松绑和交易所新规双重博弈... 2026年初,美国资本市场正经历一场旨在重振中小企业融资活力的监管变革。1月16日,SEC主席保罗·...