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.0
​com.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.0
​seata-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.0
​seata-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-openfeign
​org.springframework.bootspring-boot-devtoolsruntimetruemysqlmysql-connector-javaruntimeorg.springframework.bootspring-boot-configuration-processortrue
​org.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.0
​seata-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-jdbc
​org.mybatis.spring.bootmybatis-spring-boot-starter2.1.3org.springframework.cloudspring-cloud-starter-openfeign
​org.springframework.bootspring-boot-devtoolsruntimetruemysqlmysql-connector-javaruntimeorg.springframework.bootspring-boot-configuration-processortrue
​org.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.0
​seata-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-jdbc
​org.mybatis.spring.bootmybatis-spring-boot-starter2.1.3org.springframework.cloudspring-cloud-starter-openfeign
​org.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-starter
​io.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数据库的三张表中,通过打断点可以看到中间的信息

相关内容

热门资讯

在大吉订购APP订购交易亏损被...   近期,不少投资者反映在“大吉订购App”上投资白银、铂金等商品遭遇严重亏损。该平台宣称提供现货订...
铂银壹号APP商品订购交易亏损...   许多中小投资者误以为网上的“商品现货订购”是合规合法的理财渠道,殊不知这背后隐藏着巨大的合规风险...
兴鑫淘金APP贵金属订购交易亏...   白银、贵金属或其他商品类投资,除国家批准的正规期货交易场所及持牌期货公司外,市面上大量第三方交易...
铂银掘金APP无资质的违规平台...   铂银掘金等平台的投资者,往往是被“注册送现金”“充值返现券”“首单免亏”等广告话术吸引,进而下载...
八方淘金APP订购交易不合规,...   “八方淘金APP”“铂银掘金APP”“铂银壹号APP”等软件被指以“现货订购”为名,实际采用高杠...
在指尖订购APP订购商品亏损被...   指尖订购APP这类平台,表面是“订购交易”,实则是披着电商外衣的非法期货陷阱。绝大多数投资者被蒙...
在犀贝易购APP做商品订购交易...   市面上打着“现货投资”“贵金属交易”旗号的APP并不少,但真正合规、受监管的平台并不多。犀贝易购...
易达淘金APP虚假商品订购交易...   易达淘金APP存在严重的虚假宣传与违规交易行为。该平台打着“商品订购”的旗号,实则通过不合规的交...
大浪淘金APP白银订购亏损被骗...   大浪淘金APP最隐蔽的套路,在于其完全封闭的内盘交易系统。表面上,它宣称与国际贵金属市场接轨;实...
一品好购APP上订购白银出现亏...   一品好购APP原名“一品订购”,运营方为上海宝智未来信息技术有限公司。近期不少投资者反映在该平台...
九州订购APP贵金属订购投资骗...   九州订购APP正通过抖.音、快手、今日头条等平台大量投放投资广告,用“5元起投”“充值返现”“0...
坚锅淘金APP交易软件并不正规...   当前,市面上大量所谓的“现货商城订购”交易软件,早已偏离了正常的实物商品买卖,演变为高杠杆、高手...
斗金订购APP贵金属期货交易骗...   斗金订购APP的投资者往往被铺天盖地的广告宣传所诱导——注册即送现金、充值返现券等看似诱人的福利...
警惕!云启购APP违规经营,披...   "5元起投、充值返现、稳赚不赔"——这些诱人的广告语背后,可能是一个精心设计的金融陷阱。  近期...
量子淘金APP贵金属投资不合规...   "4元起投""充值返券""月入过万"——这些极具诱惑力的广告语在短视频平台、社交软件上铺天盖地。...
鑫汇智投APP贵金属商品订购骗...   鑫汇智投APP非法期货投资骗局,受害者在投资过程中根本不懂交易,也不去研究和验证这个平台是否正规...
矅光智策APP平台违规经营非法...   矅光智策APP对外宣称是“商城订购”“现货交易”,但查询其经营范围,并未显示具备开展现货期货交易...
黄金珠宝怎么选?内侧刻字都代表... 潮新闻客户端 记者 马焱 通讯员 任倩影 9月8日下午,“云游杭州 乐购金秋”——“浙城·浙放心”活...
原创 冰... 最近全球国债市场正在上演魔幻一幕: 美债、日债、欧债遭遇猛烈抛售,收益率冲到几十年新高,美国财政部都...
日韩股市开盘表现分化 上证报中国证券网讯 9月9日,日韩股市开盘表现分化,韩国综合指数开盘上涨0.26%,报6972.87...