1.SETA是什么
请参考
Seata的官网地址:https://seata.io/zh-cn/
2.SEATA下载
Seata的下载地址: https://github.com/seata/seata/releases
3.SEATA的部署指南
也可以从源码中的脚本找到对应的文件
4. 本案例采用的NACOS的配置项
拷贝关于nacos的配置文件和nacos的启动脚本,到SEATA的指定的位置
在config.txt中添加对应的配置信息:(根据需求,名字可以自己编写,推荐使用应用微服务的名字,值也可以自己编写)但是必须和后面微服务的要保持一致。
seata数据库的脚本如下:
-- ----------------------------
-- Table structure for `branch_table`
-- ----------------------------
DROP TABLE IF EXISTS `branch_table`;
CREATE TABLE `branch_table` (
`branch_id` bigint(20) NOT NULL,
`xid` varchar(128) NOT NULL,
`transaction_id` bigint(20) DEFAULT NULL,
`resource_group_id` varchar(32) DEFAULT NULL,
`resource_id` varchar(256) DEFAULT NULL,
`lock_key` varchar(128) DEFAULT NULL,
`branch_type` varchar(8) DEFAULT NULL,
`status` tinyint(4) DEFAULT NULL,
`client_id` varchar(64) DEFAULT NULL,
`application_data` varchar(2000) DEFAULT NULL,
`gmt_create` datetime DEFAULT NULL,
`gmt_modified` datetime DEFAULT NULL,
PRIMARY KEY (`branch_id`),
KEY `idx_xid` (`xid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of branch_table
-- ----------------------------
-- ----------------------------
-- Table structure for `global_table`
-- ----------------------------
DROP TABLE IF EXISTS `global_table`;
CREATE TABLE `global_table` (
`xid` varchar(128) NOT NULL,
`transaction_id` bigint(20) DEFAULT NULL,
`status` tinyint(4) NOT NULL,
`application_id` varchar(32) DEFAULT NULL,
`transaction_service_group` varchar(32) DEFAULT NULL,
`transaction_name` varchar(128) DEFAULT NULL,
`timeout` int(11) DEFAULT NULL,
`begin_time` bigint(20) DEFAULT NULL,
`application_data` varchar(2000) DEFAULT NULL,
`gmt_create` datetime DEFAULT NULL,
`gmt_modified` datetime DEFAULT NULL,
PRIMARY KEY (`xid`),
KEY `idx_gmt_modified_status` (`gmt_modified`,`status`),
KEY `idx_transaction_id` (`transaction_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of global_table
-- ----------------------------
-- ----------------------------
-- Table structure for `lock_table`
-- ----------------------------
DROP TABLE IF EXISTS `lock_table`;
CREATE TABLE `lock_table` (
`row_key` varchar(128) NOT NULL,
`xid` varchar(96) DEFAULT NULL,
`transaction_id` mediumtext,
`branch_id` mediumtext,
`resource_id` varchar(256) DEFAULT NULL,
`table_name` varchar(32) DEFAULT NULL,
`pk` varchar(36) DEFAULT NULL,
`gmt_create` datetime DEFAULT NULL,
`gmt_modified` datetime DEFAULT NULL,
PRIMARY KEY (`row_key`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
参考如下图:
4.1 初始化seata在nacos中的配置
执行完毕之后,就可以看到nacos的配置中心中,出现很多配置项
4.2 启动SEATA服务
可以直接双击,也可以指定启动的端口,和启动的其它的参数
5. 微服务项目的搭建
5.1 项目描述
订单、库存、账户,用户下完订单之后,就会去扣减库存和扣减账户余额,并更新订单的状态为已经支付的状态
5.2 数据库表
订单表结构如下:
-- ----------------------------
-- Table structure for `tbl_order`
-- ----------------------------
DROP TABLE IF EXISTS `tbl_order`;
CREATE TABLE `tbl_order` (
`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',
`status` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of tbl_order
-- ----------------------------
库存表结构如下:
DROP TABLE IF EXISTS `tbl_storage`;
CREATE TABLE `tbl_storage` (
`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` (`commodity_code`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
账户表结构如下:
DROP TABLE IF EXISTS `tbl_account`;
CREATE TABLE `tbl_account` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` varchar(255) DEFAULT NULL,
`money` int(11) DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
undo_log日志结构如下:
-- 注意此处0.3.0+ 增加唯一索引 ux_undo_log
CREATE TABLE `undo_log` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`branch_id` bigint(20) NOT NULL,
`xid` varchar(100) NOT NULL,
`context` varchar(128) NOT NULL,
`rollback_info` longblob NOT NULL,
`log_status` int(11) NOT NULL,
`log_created` datetime NOT NULL,
`log_modified` datetime NOT NULL,
`ext` varchar(100) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
5.3 父工程的搭建
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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.edu</groupId>
<artifactId>microservicecloud2022</artifactId>
<version>1.0-SNAPSHOT</version>
<modules>
<module>cloud-common-api</module>
<module>cloud-provider-payment8001</module>
<module>cloud-consumer-order80</module>
<module>cloud-eureka-server7001</module>
<module>cloud-eureka-server7002</module>
<module>cloud-eureka-server7003</module>
<module>cloud-provider-payment8004</module>
<module>cloud-consumerzk-order80</module>
<module>cloud-providerconsul-payment8006</module>
<module>cloud-provider-payment8002</module>
<module>cloud-sonsumer-feign-order80</module>
<module>cloud-provider-hystrix-payment8001</module>
<module>cloud-consumer-feign-hystrix-order80</module>
<module>cloud-consumer-hystrix-dashboard9001</module>
<module>cloud-gateway-gateway9527</module>
<module>cloud-config-center-3344</module>
<module>cloud-config-client-3355</module>
<module>cloud-config-client-3366</module>
<module>cloud-stream-rabbitmq-provider8801</module>
<module>cloud-stream-rabbitmq-consumer8802</module>
<module>cloud-stream-rabbitmq-consumer8803</module>
<module>cloudalibaba-provider-payment9001</module>
<module>cloudalibaba-provider-payment9002</module>
<module>cloudalibaba-consumer-nacos-order83</module>
<module>cloudalibaba-config-nacos-client3377</module>
<module>cloudalibaba-sentinel-service8401</module>
<module>cloudalibaba-seata-order-service2001</module>
<module>cloudalibaba-seata-storage-service2002</module>
<module>cloudalibaba-seata-account-service2003</module>
</modules>
<packaging>pom</packaging>
<description>父工程进行坐标的统一的管理</description>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<junit.version>4.12</junit.version>
<lombok.version>1.18.12</lombok.version>
<mysql.version>5.1.38</mysql.version>
<druid.version>1.1.23</druid.version>
<mybatis-spring-boot.version>2.1.3</mybatis-spring-boot.version>
<spring-boot.version>2.3.2.RELEASE</spring-boot.version>
<spring-cloud.version>Hoxton.SR9</spring-cloud.version>
<spring-cloud-alibaba.version>2.2.5.RELEASE</spring-cloud-alibaba.version>
</properties>
<dependencyManagement>
<dependencies>
<!--配置springboot-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!--springcloud-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!--springcloud alibaba-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring-cloud-alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
<!--这是mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
<!--这是druid-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>${druid.version}</version>
</dependency>
<!--这是mybatis-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>${mybatis-spring-boot.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<finalName>microservicecloud2022</finalName>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<fork>true</fork>
<addResources>true</addResources>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<configuration>
<delimiters>
<delimit>@</delimit>
</delimiters>
</configuration>
</plugin>
</plugins>
</build>
</project>
5.4 通用API模块的搭建
pom文件
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>microservicecloud2022</artifactId>
<groupId>com.edu</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloud-common-api</artifactId>
<description>通用的模块</description>
<dependencies>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!--openfeign的客户端-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
</dependencies>
</project>
Account实体bean
package com.edu.springcloud.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
/**
* 这是账户的实体bean
*/
@AllArgsConstructor
@NoArgsConstructor
@Data
@Accessors(chain = true)
public class Account {
private Integer id ;
private String userId;
private int money ;
}
CommonResult实体bean
package com.edu.springcloud.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
/**
* 封装一个返回的结果集
* @param <T>
*/
@AllArgsConstructor
@NoArgsConstructor
@Data
@Accessors(chain = true)
public class CommonResult<T> {
private Integer code ;// 响应码
private String message ;// 响应消息
private T data ;// 响应的数据
/**
* 带两个参数的构造方法
* @param code
* @param message
*/
public CommonResult(Integer code, String message) {
this(code,message,null) ;
}
}
Order订单实体bean
package com.edu.springcloud.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
/**
* 订单实体bean
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
public class Order {
private Integer id ;
private String userId;
private String commodityCode ; // 商品编号
private int count ;// 订购的商品的数量
private int money ;// 订单的小计
private int status ;// 订单的状态0 为未支付 1为已经支付
}
Storage实体bean
package com.edu.springcloud.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
/**
* 这是库存的实体bean
*/
@NoArgsConstructor
@AllArgsConstructor
@Data
@Accessors(chain = true)
public class Storage {
private Integer id ;
private String commodityCode ; // 商品的编号
private int count ;// 库存的数量
}
通用Service API的调用
AccountService
package com.edu.springcloud.service;
import com.edu.springcloud.entity.Account;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
@FeignClient(value = "seata-account-service")
public interface AccountService {
@PostMapping("/reduce/account")
public void update(@RequestBody Account account) ;
}
OrderService
package com.edu.springcloud.service;
import com.edu.springcloud.entity.Order;
import org.springframework.cloud.openfeign.FeignClient;
public interface OrderService {
public void create(Order order);
public void update(int id) ;
}
StorageService
package com.edu.springcloud.service;
import com.edu.springcloud.entity.Storage;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
@FeignClient(value = "seata-storage-service")
public interface StorageService {
@PostMapping("/reduce/storage")
public void update(@RequestBody Storage storage) ;
}
5.5 账户模块的搭建
项目结构
pom文件
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>microservicecloud2022</artifactId>
<groupId>com.edu</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloudalibaba-seata-account-service2003</artifactId>
<description>账户微服务</description>
<dependencies>
<!--依赖通用的模块-->
<dependency>
<groupId>com.edu</groupId>
<artifactId>cloud-common-api</artifactId>
<version>${project.version}</version>
</dependency>
<!--这是mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--这是druid-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
</dependency>
<!--这是mybatis-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<!--springboot的web模块-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--springboot的监控模块-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--springboot的测试模块-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<!--注册到nacos 这是注册中心的坐标-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--这是配置中心的坐标-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<!--配置seata-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
<exclusions>
<exclusion>
<groupId>io.seata</groupId>
<artifactId>seata-spring-boot-starter</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.seata</groupId>
<artifactId>seata-spring-boot-starter</artifactId>
<version>1.4.0</version>
</dependency>
<!--添加热部署-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
</dependencies>
</project>
yaml配置文件
server:
port: 2003
spring:
application:
name: seata-account-service
datasource: #数据源的配置信息
type: com.alibaba.druid.pool.DruidDataSource
url: jdbc:mysql://localhost:3306/seata_account
username: root
password: root
driver-class-name: com.mysql.jdbc.Driver
#druid的其它的一些配置信息GMT%2B8
initialSize: 5
minIdle: 5
maxActive: 20
maxWait: 60000
timeBetweenEvictionRunsMillis: 60000
minEvictableIdleTimeMillis: 300000
validationQuery: SELECT 1 FROM DUAL
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
poolPreparedStatements: true
# 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
filters: stat,wall
maxPoolPreparedStatementPerConnectionSize: 20
useGlobalDataSourceStat: true
connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500
cloud:
nacos:
discovery:
server-addr: localhost:8848
config:
server-addr: localhost:8848 #nacos配置中心的地址
#file-extension: yaml #注册中心配置文件的后缀格式
group: SEATA_GROUP
mybatis:
mapper-locations: classpath:mybatis/mapper/*.xml
config-location: classpath:mybatis/mybatis-config.xml
management:
endpoints:
web:
exposure:
include: '*'
seata:
data-source-proxy-mode: AT
tx-service-group: seata-account-service
enabled: true
service:
vgroup-mapping.seata-account-service: default
registry.conf
registry {
# file 、nacos 、eureka、redis、zk、consul、etcd3、sofa
type = "nacos"
nacos {
serverAddr = "localhost:8848"
group = "SEATA_GROUP"
namespace = "public"
cluster = "default"
}
}
config {
# file、nacos 、apollo、zk、consul、etcd3
type = "nacos"
nacos {
serverAddr = "localhost:8848"
group = "SEATA_GROUP"
namespace = "public"
cluster = "default"
}
}
mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--<settings>
<setting name="cacheEnabled" value="true"/><!– 二级缓存开启 –>
</settings>-->
<typeAliases>
<package name="com.edu.springcloud.entity"/>
</typeAliases>
</configuration>
AccountMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.edu.springcloud.mapper.AccountMapper">
<!--根据商品的编号,来减少库存-->
<update id="update" parameterType="Account">
UPDATE tbl_account SET `money`=`money` - #{money} WHERE user_id=#{userId}
</update>
</mapper>
MyDataSourceConfig.java
package com.edu.springcloud.config;
import com.alibaba.druid.pool.DruidDataSource;
import io.seata.rm.datasource.DataSourceProxy;
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 MyDataSourceConfig {
@Bean
@ConfigurationProperties(prefix = "spring.datasource")
public DruidDataSource druidDataSource() {
return new DruidDataSource();
}
// @Primary
// @Bean
// public DataSourceProxy dataSource(DruidDataSource druidDataSource) {
// return new DataSourceProxy(druidDataSource);
// }
}
AccountController.java
package com.edu.springcloud.controller;
import com.edu.springcloud.entity.Account;
import com.edu.springcloud.entity.CommonResult;
import com.edu.springcloud.service.AccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class AccountController {
@Autowired
private AccountService accountService ;
@PostMapping("/reduce/account")
public CommonResult<Account> reduceAccount(@RequestBody Account account) {
accountService.update(account);
return new CommonResult<>(200,"扣款成功",account) ;
}
}
AccountMapper.java
package com.edu.springcloud.mapper;
import com.edu.springcloud.entity.Account;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface AccountMapper {
public void update(Account account) ;
}
AccountServiceImpl.java
package com.edu.springcloud.service.impl;
import com.edu.springcloud.entity.Account;
import com.edu.springcloud.mapper.AccountMapper;
import com.edu.springcloud.service.AccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class AccountServiceImpl implements AccountService {
@Autowired
private AccountMapper accountMapper ;
@Override
public void update(Account account) {
accountMapper.update(account);
}
}
SeataAccount2003_APP.java
package com.edu.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
public class SeataAccount2003_APP {
public static void main(String[] args) {
SpringApplication.run(SeataAccount2003_APP.class,args) ;
}
}
5.6 库存模块的搭建
结构图如下:
pom文件:
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>microservicecloud2022</artifactId>
<groupId>com.edu</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloudalibaba-seata-storage-service2002</artifactId>
<description>库存微服务</description>
<dependencies>
<!--依赖通用的模块-->
<dependency>
<groupId>com.edu</groupId>
<artifactId>cloud-common-api</artifactId>
<version>${project.version}</version>
</dependency>
<!--这是mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--这是druid-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
</dependency>
<!--这是mybatis-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<!--springboot的web模块-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--springboot的监控模块-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--springboot的测试模块-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<!--注册到nacos 这是注册中心的坐标-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--这是配置中心的坐标-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<!--配置seata-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
<exclusions>
<exclusion>
<groupId>io.seata</groupId>
<artifactId>seata-spring-boot-starter</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.seata</groupId>
<artifactId>seata-spring-boot-starter</artifactId>
<version>1.4.0</version>
</dependency>
<!--添加热部署-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
</dependencies>
</project>
yaml文件
server:
port: 2002
spring:
application:
name: seata-storage-service
datasource: #数据源的配置信息
type: com.alibaba.druid.pool.DruidDataSource
url: jdbc:mysql://localhost:3306/seata_storage
username: root
password: root
driver-class-name: com.mysql.jdbc.Driver
#druid的其它的一些配置信息GMT%2B8
initialSize: 5
minIdle: 5
maxActive: 20
maxWait: 60000
timeBetweenEvictionRunsMillis: 60000
minEvictableIdleTimeMillis: 300000
validationQuery: SELECT 1 FROM DUAL
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
poolPreparedStatements: true
# 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
filters: stat,wall
maxPoolPreparedStatementPerConnectionSize: 20
useGlobalDataSourceStat: true
connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500
cloud:
nacos:
discovery:
server-addr: localhost:8848
config:
server-addr: localhost:8848 #nacos配置中心的地址
file-extension: yaml #注册中心配置文件的后缀格式
mybatis:
mapper-locations: classpath:mybatis/mapper/*.xml
config-location: classpath:mybatis/mybatis-config.xml
management:
endpoints:
web:
exposure:
include: '*'
seata:
data-source-proxy-mode: AT
tx-service-group: seata-storage-service
enabled: true
service:
vgroup-mapping.seata-storage-service: default
registry.conf
registry {
# file 、nacos 、eureka、redis、zk、consul、etcd3、sofa
type = "nacos"
nacos {
serverAddr = "localhost:8848"
group = "SEATA_GROUP"
namespace = "public"
cluster = "default"
}
}
config {
# file、nacos 、apollo、zk、consul、etcd3
type = "nacos"
nacos {
serverAddr = "localhost:8848"
group = "SEATA_GROUP"
namespace = "public"
cluster = "default"
}
}
mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--<settings>
<setting name="cacheEnabled" value="true"/><!– 二级缓存开启 –>
</settings>-->
<typeAliases>
<package name="com.edu.springcloud.entity"/>
</typeAliases>
</configuration>
StorageMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.edu.springcloud.mapper.StorageMapper">
<!--根据商品的编号,来减少库存-->
<update id="update" parameterType="Storage">
UPDATE tbl_storage SET `count`=`count`-#{count} WHERE commodity_code=#{commodityCode}
</update>
</mapper>
MyDataSourceConfig.java
package com.edu.springcloud.config;
import com.alibaba.druid.pool.DruidDataSource;
import io.seata.rm.datasource.DataSourceProxy;
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 MyDataSourceConfig {
@Bean
@ConfigurationProperties(prefix = "spring.datasource")
public DruidDataSource druidDataSource() {
return new DruidDataSource();
}
// @Primary
// @Bean
// public DataSourceProxy dataSource(DruidDataSource druidDataSource) {
// return new DataSourceProxy(druidDataSource);
// }
}
StorageController.java
package com.edu.springcloud.controller;
import com.edu.springcloud.entity.CommonResult;
import com.edu.springcloud.entity.Storage;
import com.edu.springcloud.service.StorageService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class StorageController {
@Autowired
private StorageService storageService ;
@PostMapping("/reduce/storage")
public CommonResult<Storage> reduceStorage(@RequestBody Storage storage) {
storageService.update(storage);
return new CommonResult<>(200,"库存减少成功...",storage) ;
}
}
StorageMapper.java
package com.edu.springcloud.mapper;
import com.edu.springcloud.entity.Storage;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface StorageMapper {
public void update(Storage storage) ;
}
StorageServiceImpl.java
package com.edu.springcloud.service.impl;
import com.edu.springcloud.entity.Storage;
import com.edu.springcloud.mapper.StorageMapper;
import com.edu.springcloud.service.StorageService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class StorageServiceImpl implements StorageService {
@Autowired
private StorageMapper storageMapper ;
@Override
public void update(Storage storage) {
storageMapper.update(storage);
}
}
SeataStorage2002_APP.java
package com.edu.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
public class SeataStorage2002_APP {
public static void main(String[] args) {
SpringApplication.run(SeataStorage2002_APP.class,args) ;
}
}
5.7 订单模块的搭建
结构图如下
pom
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>microservicecloud2022</artifactId>
<groupId>com.edu</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloudalibaba-seata-order-service2001</artifactId>
<description>订单微服务</description>
<dependencies>
<!--依赖通用的模块-->
<dependency>
<groupId>com.edu</groupId>
<artifactId>cloud-common-api</artifactId>
<version>${project.version}</version>
</dependency>
<!--这是mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--这是druid-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
</dependency>
<!--这是mybatis-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<!--springboot的web模块-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--springboot的监控模块-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--springboot的测试模块-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<!--注册到nacos 这是注册中心的坐标-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--这是配置中心的坐标-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<!--配置seata-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
<exclusions>
<exclusion>
<groupId>io.seata</groupId>
<artifactId>seata-spring-boot-starter</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.seata</groupId>
<artifactId>seata-spring-boot-starter</artifactId>
<version>1.4.0</version>
</dependency>
<!--添加热部署-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
</dependencies>
</project>
yaml文件
server:
port: 2001
spring:
application:
name: seata-order-service
datasource: #数据源的配置信息
type: com.alibaba.druid.pool.DruidDataSource
url: jdbc:mysql://localhost:3306/seata_order
username: root
password: root
driver-class-name: com.mysql.jdbc.Driver
#druid的其它的一些配置信息GMT%2B8
initialSize: 5
minIdle: 5
maxActive: 20
maxWait: 60000
timeBetweenEvictionRunsMillis: 60000
minEvictableIdleTimeMillis: 300000
validationQuery: SELECT 1 FROM DUAL
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
poolPreparedStatements: true
# 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
filters: stat,wall
maxPoolPreparedStatementPerConnectionSize: 20
useGlobalDataSourceStat: true
connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500
cloud:
nacos:
discovery:
server-addr: localhost:8848
config:
server-addr: localhost:8848 #nacos配置中心的地址
file-extension: yaml #注册中心配置文件的后缀格式
mybatis:
mapper-locations: classpath:mybatis/mapper/*.xml
config-location: classpath:mybatis/mybatis-config.xml
management:
endpoints:
web:
exposure:
include: '*'
seata:
data-source-proxy-mode: AT
tx-service-group: seata-order-service
enabled: true
service:
vgroup-mapping.seata-order-service: default
registry.conf
registry {
# file 、nacos 、eureka、redis、zk、consul、etcd3、sofa
type = "nacos"
nacos {
serverAddr = "localhost:8848"
group = "SEATA_GROUP"
namespace = "public"
cluster = "default"
}
}
config {
# file、nacos 、apollo、zk、consul、etcd3
type = "nacos"
nacos {
serverAddr = "localhost:8848"
group = "SEATA_GROUP"
namespace = "public"
cluster = "default"
}
}
mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--<settings>
<setting name="cacheEnabled" value="true"/><!– 二级缓存开启 –>
</settings>-->
<typeAliases>
<package name="com.edu.springcloud.entity"/>
</typeAliases>
</configuration>
OrderMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.edu.springcloud.mapper.OrderMapper">
<!--新增操作-->
<insert id="create" parameterType="Order" useGeneratedKeys="true" keyProperty="id" keyColumn="id">
INSERT INTO tbl_order(`user_id`,`commodity_code`,`count`,`money`,`status`) values(#{userId},#{commodityCode},#{count},#{money},#{status})
</insert>
<!--根据订单的编号来更新订单的状态-->
<update id="update" parameterType="int">
update tbl_order set status=1 where id=#{id}
</update>
</mapper>
MyDataSourceConfig.java
package com.edu.springcloud.config;
import com.alibaba.druid.pool.DruidDataSource;
import io.seata.rm.datasource.DataSourceProxy;
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 MyDataSourceConfig {
@Bean
@ConfigurationProperties(prefix = "spring.datasource")
public DruidDataSource druidDataSource() {
return new DruidDataSource();
}
// @Primary
// @Bean
// public DataSourceProxy dataSource(DruidDataSource druidDataSource) {
// return new DataSourceProxy(druidDataSource);
// }
}
OrderController.java
package com.edu.springcloud.controller;
import com.edu.springcloud.entity.CommonResult;
import com.edu.springcloud.entity.Order;
import com.edu.springcloud.service.OrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class OrderController {
@Autowired
private OrderService orderService ;
@GetMapping("/create/order")
public CommonResult<Order> createOrder(Order order) {
orderService.create(order);
return new CommonResult<Order>(200,"创建订单成功").setData(order) ;
}
}
OrderMapper.java
package com.edu.springcloud.mapper;
import com.edu.springcloud.entity.Order;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface OrderMapper {
public void create(Order order);
public void update(int id) ;
}
OrderServiceImpl.java
package com.edu.springcloud.service.impl;
import com.edu.springcloud.entity.Account;
import com.edu.springcloud.entity.Order;
import com.edu.springcloud.entity.Storage;
import com.edu.springcloud.mapper.OrderMapper;
import com.edu.springcloud.service.AccountService;
import com.edu.springcloud.service.OrderService;
import com.edu.springcloud.service.StorageService;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
@Slf4j
public class OrderServiceImpl implements OrderService {
@Autowired
private OrderMapper orderMapper ;
@Autowired
private StorageService storageService ;
@Autowired
private AccountService accountService ;
@GlobalTransactional(name="global_create",rollbackFor = Throwable.class)
@Override
public void create(Order order) {
log.info("开始创建订单");
orderMapper.create(order);
log.info("订单创建完毕....");
log.info("开始减少库存.....");
Storage storage = new Storage();
storage.setCommodityCode(order.getCommodityCode()) ;// 商品编号
storage.setCount(order.getCount()) ;// 商品的数量
storageService.update(storage);
log.info("库存减少成功.....");
int num = 10 / 0 ;
log.info("开始更新账户");
Account account = new Account() ;
account.setUserId(order.getUserId());
account.setMoney(order.getMoney());
accountService.update(account);
log.info("更新成功");
log.info("开始更新订单的状态");
orderMapper.update(order.getId());
log.info("更新订单的状态成功");
}
@Override
public void update(int id) {
orderMapper.update(id);
}
}
SeataOrder2001_APP.java
package com.edu.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients(basePackages = "com.edu.springcloud.service")
public class SeataOrder2001_APP {
public static void main(String[] args) {
SpringApplication.run(SeataOrder2001_APP.class,args) ;
}
}
5.8 测试
启动nacos
启动seata
启动账户模块
启动库存模块
启动订单模块