近期尝试进行数据分片,并结合seata,遇到了一堆问题,现将一些内容成果记录如下。
使用的是springboot2.6.13,shardingsphere5.2.1,mybatis使用3.4.3.4,nacos2.0.4,seata使用1.6.1,同时nacos及seata使用docker部署。
1、docker中中间件安装
1.1 nacos安装
docker pull swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/nacos/nacos-server:v2.0.4
docker tag swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/nacos/nacos-server:v2.0.4 docker.io/nacos/nacos-server:v2.0.4
运行nacos
docker run --restart=always -e MODE=standalone -p 8848:8848 -p 9848:9848 -p 9849:9849 --name nacos -d nacos/nacos-server:v2.0.4
1.2 seata安装
docker pull swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/seataio/seata-server:1.6.1
docker tag swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/seataio/seata-server:1.6.1 docker.io/seataio/seata-server:1.6.1
复制配置文件,先运行一个临时的:
docker run -d --name seata-server -p 8091:8091 -p 7091:7091 seataio/seata-server:1.6.1
创建并复制配置文件
mkdir /myweb/seata-server
docker cp seata-server:/seata-server/resources /myweb/seata-server/resources
删除多余的docker
docker rm -f seata-server
重新运行:
docker run -d --name seata-server -p 8091:8091 -p 7091:7091 \
-v /myweb/seata-server/resources:/seata-server/resources \
-e SEATA_CONFIG_NAME=file:/seata-server/resources/registry \
-e SEATA_IP=192.168.15.10 \
-e SEATA_PORT=8091 \
-e SEATA_CONFIG_TYPE=nacos \
-e SEATA_CONFIG_NACOS_SERVER_ADDR=192.168.15.10:8848 \
-e SEATA_CONFIG_NACOS_GROUP=SEATA_GROUP \
-e SEATA_REGISTRY_TYPE=nacos \
-e SEATA_REGISTRY_NACOS_APPLICATION=seata-server \
-e SEATA_REGISTRY_NACOS_SERVER_ADDR=192.168.15.10:8848 \
-e SEATA_REGISTRY_NACOS_GROUP=SEATA_GROUP \
-e SEATA_STORE_MODE=file \
seataio/seata-server:1.6.1
nacos增加一个配置:
ID:seataServer.properties
group: SEATA_GROUP
格式:Properties
内容:
store.mode=file
store.file.dir=file_store/data
store.file.maxBranchSessionSize=16384
store.file.maxGlobalSessionTimeout=3600000
store.file.fileWriteBufferCacheSize=16384
store.file.flushDiskMode=async
service.vgroupMapping.default-tx-group=default
service.default.grouplist=192.168.15.10:8091
service.enableDegrade=false
service.disableGlobalTransaction=false
transport.type=TCP
transport.server=NIO
transport.heartbeat=true
transport.enableClientBatchSendRequest=false
transport.threadFactory.bossThreadPrefix=NettyBoss
transport.threadFactory.workerThreadPrefix=NettyServerNIOWorker
transport.threadFactory.serverExecutorThreadPrefix=NettyServerBizHandler
transport.threadFactory.shareBossWorker=false
transport.threadFactory.clientSelectorThreadPrefix=NettyClientSelector
transport.threadFactory.clientSelectorThreadSize=1
transport.threadFactory.clientWorkerThreadPrefix=NettyClientWorkerThread
2、父工程的配置
pom.xml
<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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.rainpet</groupId>
<artifactId>springcloud03</artifactId>
<version>1.0-SNAPSHOT</version>
<name>Archetype - springcloud03</name>
<url>http://maven.apache.org</url>
<modules>
<module>nacos01</module>
<module>nacos02</module>
<module>nacos-config01</module>
<module>seata-order</module>
<module>seata-order-sharding</module>
<module>commons</module>
<module>seata-inventory</module>
</modules>
<packaging>pom</packaging>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<spring-boot.version>2.6.13</spring-boot.version>
<log4j.version>1.2.17</log4j.version>
<junit.version>4.12</junit.version>
<spring-cloud.version>2021.0.5</spring-cloud.version>
<spring-cloud-alibaba.version>2021.0.5.0</spring-cloud-alibaba.version>
<mysql.version>8.0.29</mysql.version>
<druid.version>1.2.23</druid.version>
<mybatis.spring.boot.version>3.5.1</mybatis.spring.boot.version>
<mybatis-plus.spring.boot.version>3.4.3.4</mybatis-plus.spring.boot.version>
<lombok.version>1.18.22</lombok.version>
<jjwt.version>0.9.1</jjwt.version>
<fastjson.version>2.0.53</fastjson.version>
<nacos.version>2.0.4</nacos.version>
<seata.version>1.6.1</seata.version>
<shardingsphere.version>5.2.1</shardingsphere.version>
<spring-pagehelper.version>1.4.6</spring-pagehelper.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>${spring-boot.version}</version>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<!--type:pom scope:import将上级依赖传递到子模块-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<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>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-security</artifactId>
<version>2.2.5.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
<version>2.2.5.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-dubbo</artifactId>
<version>0.9.0.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatis-plus.spring.boot.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>${jjwt.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2</artifactId>
<version>${fastjson.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
<version>${spring-cloud-alibaba.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<version>${spring-cloud-alibaba.version}</version>
</dependency>
<dependency>
<groupId>io.seata</groupId>
<artifactId>seata-spring-boot-starter</artifactId>
<version>${seata.version}</version>
</dependency>
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId>
<version>${shardingsphere.version}</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>${jjwt.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
</project>
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>
<parent>
<groupId>org.rainpet</groupId>
<artifactId>springcloud03</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>seata-order-sharding</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatis-plus.spring.boot.version}</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.rainpet</groupId>
<artifactId>commons</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
</dependency>
<dependency>
<groupId>io.seata</groupId>
<artifactId>seata-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.antlr</groupId>
<artifactId>antlr4-runtime</artifactId>
<version>4.9.2</version>
</dependency>
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId>
<version>${shardingsphere.version}</version>
</dependency>
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>1.33</version>
</dependency>
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>${spring-pagehelper.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring-boot.version}</version>
<configuration>
<mainClass>org.rainpet.AppMain8010</mainClass>
<!-- <skip>true</skip>-->
</configuration>
<executions>
<execution>
<id>repackage</id>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
4、application.yml
server:
port: 8010
spring:
profiles:
active: local
mybatis-plus:
mapper-locations: classpath:/mapper/*.xml
type-aliases-package: org.rainpet.entity
configuration:
map-underscore-to-camel-case: true
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
cache-enabled: true
global-config:
db-config:
id-type: auto
banner: false
logging:
level:
# io.seata: DEBUG # 开启Seata DEBUG日志
org.apache.shardingsphere: info # 开启ShardingSphere DEBUG日志
5、application-local.yml
spring:
main:
allow-bean-definition-overriding: true # 允许覆盖Bean定义
application:
name: seata-order
cloud:
nacos:
discovery:
server-addr: 192.168.15.10:8848
shardingsphere:
datasource:
names: ds0,ds1
ds0:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
jdbc-url: jdbc:mysql://localhost:3306/mall?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=utf-8
username: hau
password: 123123
# data-source-proxy: true
ds1:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
jdbc-url: jdbc:mysql://localhost:3306/mall2?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=utf-8
username: hau
password: 123123
# data-source-proxy: true
rules:
sharding:
undo_log:
actual-data-nodes: ds0.undo_log
tables:
t_order: #需要分表的物理表名
actual-data-nodes: ds$->{0..1}.t_order
database-strategy:
standard:
sharding-column: id
sharding-algorithm-name: database-inline
# key-generate-strategy:
# column: id
# key-generator-name: snowflake
sharding-algorithms:
database-inline:
type: INLINE
props:
algorithm-expression: ds$->{id % 2}
props:
sql.show: true
sql-simple: true # 关闭ShardingSphere的SQL解析
xa-transaction-manager-type: Seata
seata:
enabled: true
enable-auto-data-source-proxy: true
use-jdk-proxy: true # 使用JDK代理避免CGLIB冲突
data-source-proxy-mode: AT # 数据源代理模式,AT模式是默认的事务模式,支持XA和TCC等事务模式
mode: AT # 事务模式,AT是默认的事务模式
application-id: ${spring.application.name}
tx-service-group: default # 事务组名,默认是default,此处要与seata-server配置 nacos中seataServer.properties的tx-service-group一致
service:
vgroup-mapping:
default: default #第一个default 与tx-service-group=内容一致
# disable-global-transaction: false
grouplist:
default: 192.168.15.10:8091
client:
# conf: classpath:seata.conf
undo:
data-source-proxy-mode: AT #AT模式下,undo_log表的分库分表策略
rm:
report-success-enable: true
registry:
type: nacos
nacos:
server-addr: 192.168.15.10:8848
# app-name: ${spring.application.name}
group: SEATA_GROUP
# namespace: 512505d7-f5c7-4d05-a5c5-c0c0d0e0f0a0
username: nacos
password: nacos
cluster: default
application: seata-server #此处其实是seata-server配置的应用名,是和seata-server配置的application一致
config:
type: nacos
nacos:
server-addr: 192.168.15.10:8848
group: SEATA_GROUP
# namespace: 512505d7-f5c7-4d05-a5c5-c0c0d0e0f0a0
username: nacos
password: nacos
data-id: seataServer.properties
# saga:
# enabled: true # 启用Saga模式 还有如AT模式等,默认为AT模式
6、主程序,seataOrderSharding8010.java
package org.rainpet;
import io.seata.rm.datasource.DataSourceProxy;
import io.seata.spring.annotation.GlobalTransactionScanner;
import lombok.experimental.var;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.sql.DataSource;
@SpringBootApplication
@MapperScan("org.rainpet.mapper")
@EnableDiscoveryClient
//@EnableAutoDataSourceProxy
@EnableFeignClients
@EnableTransactionManagement
public class seataOrderSharding8010 {
@Autowired
private DataSource dataSource;
public static void main(String[] args) {
var ctx = SpringApplication.run(seataOrderSharding8010.class, args);
DataSource ds = ctx.getBean(DataSource.class);
System.out.println("当前DataSource类型: " + ds.getClass().getName());
}
// @Bean
// public GlobalTransactionScanner globalTransactionScanner() {
// return new GlobalTransactionScanner("seata-order", "default-tx-group");
// }
}
7、OrderController.java
package org.rainpet.controller;
import org.rainpet.entity.Order;
import org.rainpet.mapper.OrderMapper;
import org.rainpet.service.OrderService;
import org.rainpet.vo.ResponseSet;
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;
import java.time.LocalDateTime;
import java.util.List;
@RestController
@RequestMapping("/order")
public class OrderController {
@Autowired
private OrderMapper mapper;
@Autowired
private OrderService service;
@GetMapping("/list")
public List<Order> getOrderList(){
return mapper.selectList(null);
}
@GetMapping("/add")
public ResponseSet addOrder(){
service.addOrder();
return new ResponseSet("200", "添加成功",null);
}
@GetMapping("/add2")
public ResponseSet addOrder2(){
service.addOrderWithException();
return new ResponseSet("200", "添加成功",null);
}
}
8、OrderService.java
package org.rainpet.service;
public interface OrderService {
public void addOrder();
public void addOrderWithException();
}
9、InventoryService.java
package org.rainpet.service;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
@FeignClient(name = "seata-inventory")
public interface InventoryService {
@GetMapping("/inv/add")
public String addInventory();
}
10、OrderServiceImpl.yml
package org.rainpet.service.impl;
import io.seata.spring.annotation.GlobalTransactional;
import org.rainpet.entity.Order;
import org.rainpet.mapper.OrderMapper;
import org.rainpet.service.InventoryService;
import org.rainpet.service.OrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
@Service
public class OrderServiceImpl implements OrderService {
@Autowired
private InventoryService inventoryService;
@Autowired
private OrderMapper mapper;
@Override
@GlobalTransactional(rollbackFor = Exception.class)
@Transactional(rollbackFor = Exception.class)
public void addOrder() {
Order order = new Order();
order.setOrderTime(LocalDateTime.now());
order.setOrderAddress("上海");
order.setOrderType(1);
mapper.insert( order);// 插入订单数据
inventoryService.addInventory();// 调用库存服务
// if(true)throw new RuntimeException("测试异常回滚");
}
@Override
@GlobalTransactional(rollbackFor = Exception.class)
@Transactional(rollbackFor = Exception.class)
public void addOrderWithException() {
Order order = new Order();
order.setOrderTime(LocalDateTime.now());
order.setOrderAddress("北京");
order.setOrderType(2);
mapper.insert( order);// 插入订单数据
inventoryService.addInventory();// 调用库存服务
if(true)throw new RuntimeException("测试异常回滚");
}
}
11、Inventory.java
package org.rainpet.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.math.BigDecimal;
@Data
@TableName("t_inventory")
public class Inventory {
@TableId(value = "inv_id", type = IdType.AUTO)
private Integer invId;
private String invName;
private BigDecimal invQty;
}
12、Order.java
package org.rainpet.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDateTime;
@Data
@NoArgsConstructor
@TableName("t_order")
public class Order {
@TableId(type = IdType.ASSIGN_ID) // 使用雪花算法生成ID
private Long id;
// private Integer orderId = 0;
private LocalDateTime orderTime;
private String orderAddress;
private Integer orderType;
}
13、InventoryMapper.java
package org.rainpet.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.rainpet.entity.Inventory;
import org.springframework.stereotype.Repository;
//@Repository
public interface InventoryMapper extends BaseMapper<Inventory> {
}
14、OrderMapper.java
package org.rainpet.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.rainpet.entity.Order;
//@Mapper
public interface OrderMapper extends BaseMapper<Order> {
// public void save(Order order);
}
15、ResponseSet.java
package org.rainpet.vo;
import lombok.Data;
@Data
public class ResponseSet {
private String code;
private String msg;
private Object data;
private String requestId;
public ResponseSet(String code, String msg, Object data, String requestId) {
this.code = code;
this.msg = msg;
this.data = data;
this.requestId = requestId;
}
public ResponseSet(String code, String msg, Object data) {
this.code = code;
this.msg = msg;
this.data = data;
}
}
还有一点,之前当有异常抛出时,一直没有回滚,后来发现与springboot的版本有关系,我使用springboot2.6.13就可以,但是springboot2.6.3不行。
2095

被折叠的 条评论
为什么被折叠?



