一.簡單介紹
本demo大部分采用官網(wǎng)的例子寇壳,涉及到一個(gè)業(yè)務(wù)入口服務(wù)(business)璧眠,兩個(gè)微服務(wù)(訂單服務(wù)-order埂材,倉庫服務(wù)-stock),采用nacos配置,分布式事務(wù)用Seata瞪讼。
相關(guān)版本:nacos 采用1.1.4 ,Seata采用seata-1.4.0,
二.相關(guān)數(shù)據(jù)庫準(zhǔn)備
需要搭建兩個(gè)數(shù)據(jù)庫(采用mysql數(shù)據(jù)庫)若河,訂單服務(wù)連接seata-order幅狮,倉庫服務(wù)連接seata-stock募强,
undo_log建表語句如下(官網(wǎng)地址):
-- for AT mode you must to init this sql for you business database. the seata server not need it.
CREATE TABLE IF NOT EXISTS `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
AUTO_INCREMENT = 1
DEFAULT CHARSET = utf8 COMMENT ='AT transaction mode undo table';
注意:undo_log表需要在兩個(gè)數(shù)據(jù)庫都執(zhí)行株灸。
業(yè)務(wù)表order_tbl建表sql如下:
DROP TABLE IF EXISTS `order_tbl`;
CREATE TABLE `order_tbl` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` varchar(255) DEFAULT NULL,
`commodity_code` varchar(255) DEFAULT NULL,
`count` int(11) DEFAULT 0,
`money` int(11) DEFAULT 0,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
業(yè)務(wù)表storage_tbl建表sql如下:
DROP TABLE IF EXISTS `storage_tbl`;
CREATE TABLE `storage_tbl` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`commodity_code` varchar(255) DEFAULT NULL,
`count` int(11) DEFAULT 0,
PRIMARY KEY (`id`),
UNIQUE KEY (`commodity_code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- 初始化庫存模擬數(shù)據(jù)
INSERT INTO storage_tbl (id, commodity_code, count) VALUES (1, 'product-1', 1000);
INSERT INTO storage_tbl (id, commodity_code, count) VALUES (2, 'product-2', 0);
建表成功之后,如下圖所示:
三.客服端框架搭建
具體的seata客服端框架擎值,可以參考官網(wǎng)給的例子慌烧,springCloud_nacos_seata
直接用idea搭建一個(gè)demo,組建common模塊鸠儿,business業(yè)務(wù)入口模塊屹蚊,order,stock服務(wù)模塊
1.搭建基礎(chǔ)模塊(common)
直接看common模塊pom.xml,主要是訪問數(shù)據(jù)庫的相關(guān)jar进每,和seata-all.jar
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>seate-all-parent</artifactId>
<groupId>com.seate.info</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>com.seata</groupId>
<artifactId>common</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>common</name>
<description>Demo project for Spring Boot</description>
<dependencies>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
<exclusions>
<exclusion>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.39</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.1.1</version>
</dependency>
<!--<dependency>
<groupId>io.seata</groupId>
<artifactId>seata-spring-boot-starter</artifactId>
<version>1.4.0</version>
</dependency>-->
<dependency>
<groupId>io.seata</groupId>
<artifactId>seata-all</artifactId>
<version>1.4.0</version>
</dependency>
</dependencies>
</project>
2.搭建order服務(wù)模塊(stock服務(wù)依賴的包一模一樣)
pom.xml如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.6.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.seate</groupId>
<artifactId>order</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>order</name>
<description>Demo project for Spring Boot</description>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!-- nacos -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<version> 0.9.0.RELEASE </version>
<exclusions>
<exclusion>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
<version>1.1.4</version>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
<version>2.1.0.RELEASE</version>
<exclusions>
<exclusion>
<groupId>io.seata</groupId>
<artifactId>seata-all</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<!-- mysql -->
<dependency>
<groupId>com.seata</groupId>
<artifactId>common</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<spring-cloud.version>Finchley.SR2</spring-cloud.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.yml</include>
<include>**/*.properties</include>
<include>**/*.xml</include>
<include>**/*.conf</include>
</includes>
<filtering>false</filtering>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.yml</include>
<include>**/*.properties</include>
<include>**/*.xml</include>
<include>**/*.conf</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
</project>
3.搭建business模塊
不需要連接數(shù)據(jù)庫汹粤,所以不需要引用common,但是需要單獨(dú)依賴seata-all.jar
pom.xml如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.6.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.seate</groupId>
<artifactId>business</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>business</name>
<description>Demo project for Spring Boot</description>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!-- nacos -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<version> 0.9.0.RELEASE </version>
<exclusions>
<exclusion>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
<version>1.1.4</version>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
<version>2.1.0.RELEASE</version>
<exclusions>
<exclusion>
<groupId>io.seata</groupId>
<artifactId>seata-all</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<dependency>
<groupId>io.seata</groupId>
<artifactId>seata-all</artifactId>
<version>1.4.0</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-openfeign-core</artifactId>
</dependency>
</dependencies>
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<spring-cloud.version>Finchley.SR2</spring-cloud.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.yml</include>
<include>**/*.properties</include>
<include>**/*.xml</include>
<include>**/*.conf</include>
</includes>
<filtering>false</filtering>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.yml</include>
<include>**/*.properties</include>
<include>**/*.xml</include>
<include>**/*.conf</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
</project>
上述服務(wù)搭建完成之后的目錄如下:
四.客服端配置修改
1.registry.conf文件
這個(gè)文件需要存放到根目錄田晚,order嘱兼,stock,business都需要copy一份到根目錄,并且這個(gè)文件跟seata服務(wù)端的一樣肉瓦。服務(wù)端配置可以參考上一篇文章(Seata服務(wù)端配置(nacos))
registry {
# file 遭京、nacos 、eureka泞莉、redis哪雕、zk、consul鲫趁、etcd3斯嚎、sofa
type = "nacos"
loadBalance = "RandomLoadBalance"
loadBalanceVirtualNodes = 10
nacos {
application = "seata-server"
serverAddr = "nacos的ip地址:8848"
namespace = "df2011b0-ed94-4fd2-9a33-baa6f97f5af5"
group = "SEATA_GROUP"
cluster = "default"
}
}
config {
# file、nacos 挨厚、apollo堡僻、zk、consul疫剃、etcd3
type = "nacos"
nacos {
serverAddr = "nacos的ip地址:8848"
namespace = "df2011b0-ed94-4fd2-9a33-baa6f97f5af5"
group = "SEATA_GROUP"
}
}
注:registry中的group和cluster兩個(gè)屬性很重要钉疫,不然后面服務(wù)啟動(dòng)后會(huì)報(bào)如下錯(cuò)誤:no available service found in cluster 'default', please make sure registry config correct and keep your seata server running
2.application.yml文件
order服務(wù)和stock服務(wù)配置如下:
server:
port: 8090
servlet:
context-path: /order
spring:
application:
name: order-service
cloud:
nacos:
discovery:
server-addr: nacos地址:8848
namespace: df2011b0-ed94-4fd2-9a33-baa6f97f5af5
alibaba:
seata:
tx-service-group: order-tx-grp
datasource:
druid:
url: jdbc:mysql://數(shù)據(jù)庫地址:3306/seata-order?useUnicode=true
driver-class-name: com.mysql.jdbc.Driver
username: username
password: password
feign:
hystrix:
enabled: false
stock服務(wù)的配置如下:
server:
port: 8092
servlet:
context-path: /stock
spring:
application:
name: stock-service
cloud:
alibaba:
seata:
tx-service-group: stock-tx-grp
nacos:
discovery:
server-addr: nacos地址:8848
namespace: df2011b0-ed94-4fd2-9a33-baa6f97f5af5
datasource:
druid:
url: jdbc:mysql://數(shù)據(jù)庫地址:3306/seata-stock?useUnicode=true
driver-class-name: com.mysql.jdbc.Driver
username: username
password: password
feign:
hystrix:
enabled: false
注:配置文件中的tx-service-group配置的【stock-tx-grp】必須和seata中在nacos配置的service.vgroupMapping.{事務(wù)組名稱},一致
business服務(wù)配置如下:
server:
port: 8093
servlet:
context-path: /business
spring:
application:
name: business-service
cloud:
alibaba:
seata:
tx-service-group: order-tx-grp
nacos:
discovery:
server-addr: nacos地址:8848
namespace: df2011b0-ed94-4fd2-9a33-baa6f97f5af5
3.數(shù)據(jù)庫代理配置文件(Java文件)
配置文件需要放到項(xiàng)目中,如下:
package com.seate.stock.config;
import com.alibaba.druid.pool.DruidDataSource;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import io.seata.rm.datasource.DataSourceProxy;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import javax.sql.DataSource;
@Configuration
public class MyBatisConfig {
/**
* @param sqlSessionFactory SqlSessionFactory
* @return SqlSessionTemplate
*/
@Bean
public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
return new SqlSessionTemplate(sqlSessionFactory);
}
/**
* 從配置文件獲取屬性構(gòu)造datasource巢价,注意前綴牲阁,這里用的是druid,根據(jù)自己情況配置,
* 原生datasource前綴取"spring.datasource"
*
* @return
*/
@Bean
@ConfigurationProperties(prefix = "spring.datasource.druid")
public DataSource druidDataSource() {
DruidDataSource druidDataSource = new DruidDataSource();
return druidDataSource;
}
/**
* 構(gòu)造datasource代理對象壤躲,替換原來的datasource
* @param druidDataSource
* @return
*/
@Primary
@Bean("dataSource")
public DataSourceProxy dataSourceProxy(DataSource druidDataSource) {
return new DataSourceProxy(druidDataSource);
}
@Bean(name = "sqlSessionFactory")
public SqlSessionFactory sqlSessionFactoryBean(DataSourceProxy dataSourceProxy) throws Exception {
MybatisSqlSessionFactoryBean bean = new MybatisSqlSessionFactoryBean();
bean.setDataSource(dataSourceProxy);
SqlSessionFactory factory = null;
try {
factory = bean.getObject();
} catch (Exception e) {
throw new RuntimeException(e);
}
return factory;
}
/**
* MP 自帶分頁插件
* @return
*/
@Bean
public PaginationInterceptor paginationInterceptor() {
PaginationInterceptor page = new PaginationInterceptor();
page.setDialectType("mysql");
return page;
}
}
注:AT模式下需要配置
這個(gè)配置文件需要放到order,stock服務(wù)內(nèi)城菊,如下圖:
配置類配置好之后,在應(yīng)用啟動(dòng)類中關(guān)閉SpringBoot的DataSource自動(dòng)裝載
@EnableDiscoveryClient
@EnableFeignClients
@SpringBootApplication(scanBasePackages = {"com.seate"}, exclude = DataSourceAutoConfiguration.class)
public class StockApplication {
public static void main(String[] args) {
SpringApplication.run(StockApplication.class, args);
}
}
五.編寫業(yè)務(wù)代碼
order碉克,stock中的業(yè)務(wù)代碼可以參考官網(wǎng)demo凌唬。下面只粘貼對應(yīng)service相關(guān)代碼,controller代碼參考官網(wǎng)漏麦。
business服務(wù)中代碼如下:
package com.seate.business.service;
import com.seate.business.feign.OrderFeignClient;
import com.seate.business.feign.StorageFeignClient;
import com.seate.business.vo.CommintRequest;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
/**
* 功能描述:
*
* @Author:
* @Date: 2020/12/7 17:58
*/
@Service
@Slf4j
public class BusinessService {
@Resource
private OrderFeignClient orderFeignClient;
@Resource
private StorageFeignClient storageFeignClient;
/**
* 下單:創(chuàng)建訂單客税、減庫存况褪,涉及到兩個(gè)服務(wù)
*
* @param userId
* @param commodityCode
* @param count
*/
@GlobalTransactional(rollbackFor = Exception.class)
public void placeOrder(String userId, String commodityCode, Integer count) {
CommintRequest request=new CommintRequest();
request.setUserId(userId);
request.setCommodityCode(commodityCode);
request.setCount(count);
orderFeignClient.placeOrderCommit(request);
storageFeignClient.deduct(commodityCode, count);
}
}
注:
@GlobalTransactional 開啟全局事務(wù),放在business入口處霎挟,其中通過feign調(diào)用了order和stock服務(wù)
order服務(wù)的業(yè)務(wù)處理方法如下:
package com.seate.order.service;
import com.seate.order.dao.OrderInfoDao;
import com.seate.order.feign.StorageFeignClient;
import com.seate.order.model.OrderInfo;
import com.seate.order.vo.CommintRequest;
import io.seata.core.context.RootContext;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongoProperties;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.math.BigDecimal;
/**
* 功能描述:
*
* @Author:
* @Date: 2020/12/7 17:04
*/
@Slf4j
@Service
public class OrderInfoService {
@Resource
private OrderInfoDao orderInfoDao;
public void placeOrder(CommintRequest request) {
BigDecimal orderMoney = new BigDecimal(request.getCount()).multiply(new BigDecimal(5));
OrderInfo order = new OrderInfo()
.setUserId(request.getUserId())
.setCommodityCode(request.getCommodityCode())
.setCount(request.getCount())
.setMoney(orderMoney);
orderInfoDao.insert(order);
}
}
order服務(wù)模擬訂單創(chuàng)建操作
stock服務(wù)業(yè)務(wù)代碼如下:
package com.seate.stock.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.seate.stock.dao.StorageInfoDao;
import com.seate.stock.model.StorageInfo;
import com.seate.stock.service.IStorageInfoService;
import io.seata.core.context.RootContext;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
/**
* 功能描述:
*
* @Author:
* @Date: 2020/12/7 17:44
*/
@Service
@Slf4j
public class StorageInfoService implements IStorageInfoService {
@Resource
private StorageInfoDao storageInfoDao;
/**
* 減庫存
*
* @param commodityCode
* @param count
*/
@Override
public void deduct(String commodityCode, int count) {
log.info(">>>>>>StorageInfoService begin窝剖,XID為" + RootContext.getXID());
QueryWrapper<StorageInfo> wrapper = new QueryWrapper<>();
wrapper.setEntity(new StorageInfo().setCommodityCode(commodityCode));
StorageInfo storage = storageInfoDao.selectOne(wrapper);
storage.setCount(storage.getCount() - count);
storageInfoDao.updateById(storage);
if (commodityCode.equals("product-2")) {
throw new RuntimeException("異常:模擬業(yè)務(wù)異常:Storage branch exception");
}
}
}
在stock服務(wù)中模擬拋出了異常,看order服務(wù)創(chuàng)建的訂單是否會(huì)回滾
六.進(jìn)行全局事務(wù)驗(yàn)證
啟動(dòng)nacos酥夭,seata服務(wù)赐纱,然后啟動(dòng)stock,order熬北,business服務(wù)疙描,
查看nacos服務(wù)列表如下:
上述表示各個(gè)服務(wù)都啟動(dòng)正常,并注冊到nacos成功,
查看Seata服務(wù)端日志如下:
查看order讶隐,stock起胰,business服務(wù),出現(xiàn)如下日志表示本地事務(wù)注冊成功:
1.驗(yàn)證回滾功能
初始值:訂單表order_tbl 沒有數(shù)據(jù)巫延,倉庫表庫存為10
訪問接口:http://localhost:8093/business/placeOrder/rollback
返回:
{
timestamp: "2020-12-15T11:35:48.771+0000"
status: 500
error: "Internal Server Error"
message: "status 500 reading StorageFeignClient#deduct(String,Integer); content: {"timestamp":"2020-12-15T11:35:48.663+0000","status":500,"error":"Internal Server Error","message":"異常:模擬業(yè)務(wù)異常:Storage branch exception","path":"/stock/storage/deduct"}"
path: "[/business/placeOrder/rollback](chrome-extension://gpifhhbaillafhgecomgdilnmplnoelg/business/placeOrder/rollback "Click to insert into URL field")"
}
查看order數(shù)據(jù)庫看訂單是否創(chuàng)建成功:
查看stock數(shù)據(jù)庫看庫存是否扣減:
查看order服務(wù)日志如下:
查看stock服務(wù)日志如下:
查看business服務(wù)日志如下:
2.驗(yàn)證提交功能
初始值:訂單表order_tbl 沒有數(shù)據(jù)效五,倉庫表庫存為10
訪問接口:http://localhost:8093/business/placeOrder/commit
返回值:true
查看order數(shù)據(jù)庫訂單是否創(chuàng)建成功:
查看stock數(shù)據(jù)庫庫存是否扣減:
查看order服務(wù)日志如下:
查看stock服務(wù)日志如下:
查看business服務(wù)日志如下:
七.搭建過程遇到的些異常情況
1.nacos配置讀取不到
[imeoutChecker_1] i.s.c.r.netty.NettyClientChannelManager : no available service 'null' found, please make sure registry config correct
出現(xiàn)上述異常,可能是nacos配置沒有讀取到炉峰,需要確認(rèn)下nacos的版本畏妖,看下nacos客服端版本是否和服務(wù)端不一致,或者版本較低疼阔。本demo中的nacos版本1.1.4版本戒劫,更nacos服務(wù)端版本一致
2.seata客服端和服務(wù)端版本不一致
[imeoutChecker_1] i.s.c.r.netty.NettyClientChannelManager : no available service 'default' found, please make sure registry config correct
nacos配置可以讀取,但是seata客服端版本太低婆廊,本demo服務(wù)端版本是1.4.0迅细,所以客服端版本需要升級。版本不一致也會(huì)造成上述異常
3.seata客服端版本太低
org.springframework.beans.BeanInstantiationException: Failed to instantiate [io.seata.spring.annotation.GlobalTransactionScanner]: Factory method 'globalTransactionScanner' threw exception; nested exception is io.seata.common.exception.ShouldNeverHappenException: Can't find any object of class org.springframework.context.ApplicationContext
這個(gè)原因是引用的spring-cloud-starter-alibaba-seata包中的seata-all版本太低淘邻,和服務(wù)端版本對不上茵典,需要剔除掉包中低版本的seata-all
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
<version>2.1.0.RELEASE</version>
<exclusions>
<exclusion>
<groupId>io.seata</groupId>
<artifactId>seata-all</artifactId>
</exclusion>
</exclusions>
</dependency>
本demo到這里就結(jié)束了,如果想看seata服務(wù)端搭建可以參考上一篇文章(Seata服務(wù)端搭建(nacos))