ShardingJdbc-分表;分库分表;读写分离;一主多从+分表;一主多从+分库分表;公共表;数据脱敏;分布式事务
Posted RB2010
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ShardingJdbc-分表;分库分表;读写分离;一主多从+分表;一主多从+分库分表;公共表;数据脱敏;分布式事务相关的知识,希望对你有一定的参考价值。
创建项目
一顿下一步,勾选web、lombok等插件
分表
导包
ShardingJdbc
官方最新稳定版4.1.1
<!-- https://mvnrepository.com/artifact/org.apache.shardingsphere/sharding-jdbc-spring-boot-starter -->
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-jdbc-spring-boot-starter</artifactId>
<version>4.1.1</version>
</dependency>
Mysql
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.25</version>
</dependency>
Druid
<!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.6</version>
</dependency>
MyBatisPlus
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.3</version>
</dependency>
表结构
注意:之前我这表名叫table_0,结果一直报找不到表,后来发现,不能用关键字
CREATE TABLE `master_db`.`my_table_0` (
`id` BIGINT (20) NOT NULL,
`source` VARCHAR (20),
`remark` VARCHAR (100),
PRIMARY KEY (`id`)
);
CREATE TABLE `master_db`.`my_table_1` (
`id` BIGINT (20) NOT NULL,
`source` VARCHAR (20),
`remark` VARCHAR (100),
PRIMARY KEY (`id`)
);
Yml
application-sharding_table.yml
server:
port: 80
spring:
application:
name: shardingJdbcDemo
#shardingsphere相关配置
shardingsphere:
datasource:
names: db #库名,只是名字
db: #数据源
type: com.alibaba.druid.pool.DruidDataSource
driverClassName: com.mysql.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/master_db?useUnicode=true&characterEncoding=utf8&useSSL=false&allowMultiQueries=true&serverTimezone=GMT
username: root
password: 123
sharding: #指定表的分片规则
tables: # 看到table "s" ,就知道可配置多个
my_table: # 指定表名,此名必须和model中 @TableName(value = "my_table") 一致
actualDataNodes: db.my_table_$->{0..1} #创建了两个表,下标0和1,所以此处配置你懂的
tableStrategy:
inline: # 指定表的分片策略
shardingColumn: id #参与分片运算的列名
algorithmExpression: my_table_$->{id % 2} #分片规则
keyGenerator: # 指定表的主键生成策略
type: SNOWFLAKE #SNOWFLAKE
column: id #指定主键
props:
sql:
show: true #输出日志
至此配置完毕,运行效果见下方代码
分库分表
java代码都不改,只改数据库及yml
数据库
master_db、 slave_db1、 slave_db2
库中分别创建my_table_0、my_table_1,结构同 上
Yml
application-sharding_master_slave.yml
spring:
application:
name: shardingJdbcDemo
#shardingsphere相关配置
shardingsphere:
datasource:
names: db0,db1,db2 #库名,只是名字
db0: #主库
type: com.alibaba.druid.pool.DruidDataSource
driverClassName: com.mysql.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/master_db?useUnicode=true&characterEncoding=utf8&useSSL=false&allowMultiQueries=true&serverTimezone=GMT
username: root
password: 123
db1: #从库1
type: com.alibaba.druid.pool.DruidDataSource
driverClassName: com.mysql.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/slave_db1?useUnicode=true&characterEncoding=utf8&useSSL=false&allowMultiQueries=true&serverTimezone=GMT
username: root
password: 123
db2: #从库2
type: com.alibaba.druid.pool.DruidDataSource
driverClassName: com.mysql.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/slave_db2?useUnicode=true&characterEncoding=utf8&useSSL=false&allowMultiQueries=true&serverTimezone=GMT
username: root
password: 123
#分库分表start
sharding: #指定表的分片规则
tables: # 看到table "s" ,就知道可配置多个
my_table: # 指定表名,此名必须和model中 @TableName(value = "my_table") 一致
actualDataNodes: db$->{0..2}.my_table_$->{0..1} #创建了两个表,下标0和1,所以此处配置你懂的
databaseStrategy:
inline: # 指定表的分片策略
shardingColumn: id #参与分片运算的列名
algorithmExpression: db$->{id % 3} #分片算法,分了三个库,所以要%3
tableStrategy:
inline: # 指定表的分片策略
shardingColumn: id #参与分片运算的列名
algorithmExpression: my_table_$->{id % 2} #分片算法
keyGenerator: # 指定表的主键生成策略
type: SNOWFLAKE #SNOWFLAKE
column: id #指定主键
#分库分表end
props:
sql:
show: true #输出日志
然后继续访问第一步的save&select方法就可看到效果了,配置文件中写的主从库没有实际意义,起错名字了,实际都会往里面写
读写分离
数据库
模拟主从,不做MySql真正的主从同步
上面做表分片时已经创建好了主库master_db 再创建两个库 slave_db1 slave_db2
三个库表结构一致
master_db表中无数据
slave_db1 表数据如下
"id" "source" "remark"
"1" "source1" "remark1"
slave_db2 表数据如下
"id" "source" "remark"
"1" "source2" "remark2"
Yml
application-master_slave.yml
spring:
application:
name: shardingJdbcDemo
#shardingsphere相关配置
shardingsphere:
datasource:
names: masterdb,slavedb1,slavedb2 #库名,只是名字
masterdb: #主库
type: com.alibaba.druid.pool.DruidDataSource
driverClassName: com.mysql.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/master_db?useUnicode=true&characterEncoding=utf8&useSSL=false&allowMultiQueries=true&serverTimezone=GMT
username: root
password: 123
slavedb1: #从库1
type: com.alibaba.druid.pool.DruidDataSource
driverClassName: com.mysql.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/slave_db1?useUnicode=true&characterEncoding=utf8&useSSL=false&allowMultiQueries=true&serverTimezone=GMT
username: root
password: 123
slavedb2: #从库2
type: com.alibaba.druid.pool.DruidDataSource
driverClassName: com.mysql.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/slave_db2?useUnicode=true&characterEncoding=utf8&useSSL=false&allowMultiQueries=true&serverTimezone=GMT
username: root
password: 123
masterslave:
name: dbs
master-data-source-name: masterdb #主库
slave-data-source-names: slavedb1,slavedb2 #多个从库
load-balance-algorithm-type: ROUND_ROBIN #RANDOM随机 ROUND_ROBIN 轮训
props:
sql:
show: true #输出日志
这时,访问上面搭好的项目,即可进行读写分离,代码见上方链接
其他
只请求主库
在请求上方添加如下代码即可
// HintManager hintManager = HintManager.getInstance();
// hintManager.setMasterRouteOnly();
@GetMapping("select")
public PageInfo select(int pageNum,int pageSize,Long id){
// HintManager hintManager = HintManager.getInstance();
// hintManager.setMasterRouteOnly();
PageHelper.startPage(pageNum,pageSize);
QueryWrapper<Table0> queryWrapper=new QueryWrapper();
if(!StringUtils.isEmpty(id)) {
queryWrapper.eq("id", id);
}
List<Table0> list = table0Service.list(queryWrapper);
PageInfo pageInfo = new PageInfo<>(list);
return pageInfo;
}
读写分离判断逻辑代码
大致的流程是shardingJdbc根据sql获得对应的sqlStatement,然后只有SelectStatement的才走从库
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.shardingsphere.masterslave.route.engine.impl;
import lombok.RequiredArgsConstructor;
import org.apache.shardingsphere.api.hint.HintManager;
import org.apache.shardingsphere.core.rule.MasterSlaveRule;
import org.apache.shardingsphere.sql.parser.sql.statement.SQLStatement;
import org.apache.shardingsphere.sql.parser.sql.statement.dml.SelectStatement;
import java.util.ArrayList;
/**
* Data source router for master-slave.
*/
@RequiredArgsConstructor
public final class MasterSlaveDataSourceRouter {
private final MasterSlaveRule masterSlaveRule;
/**
* Route.
*
* @param sqlStatement SQL statement
* @return data source name
*/
public String route(final SQLStatement sqlStatement) {
if (isMasterRoute(sqlStatement)) {
MasterVisitedManager.setMasterVisited();
return masterSlaveRule.getMasterDataSourceName();
}
return masterSlaveRule.getLoadBalanceAlgorithm().getDataSource(
masterSlaveRule.getName(), masterSlaveRule.getMasterDataSourceName(), new ArrayList<>(masterSlaveRule.getSlaveDataSourceNames()));
}
private boolean isMasterRoute(final SQLStatement sqlStatement) {
return containsLockSegment(sqlStatement) || !(sqlStatement instanceof SelectStatement) || MasterVisitedManager.isMasterVisited() || HintManager.isMasterRouteOnly();
}
private boolean containsLockSegment(final SQLStatement sqlStatement) {
return sqlStatement instanceof SelectStatement && ((SelecStatement) sqlStatement).getLock().isPresent();
}
}
一主多从+分表
上面实现了一主多从和表分片,现在把它整合到一起
java代码还是没改,主要改的还是Yml
Yml
application-sharding_db_table_oneMaster_slaves.yml
关键配置见 masterSlaveRule,分片配置未改
#一主多从+表分片
spring:
application:
name: shardingJdbcDemo
#shardingsphere相关配置
shardingsphere:
datasource:
names: db0,db1,db2 #库名,只是名字
db0: #主库
type: com.alibaba.druid.pool.DruidDataSource
driverClassName: com.mysql.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/master_db?useUnicode=true&characterEncoding=utf8&useSSL=false&allowMultiQueries=true&serverTimezone=GMT
username: root
password: 123
db1: #从库1
type: com.alibaba.druid.pool.DruidDataSource
driverClassName: com.mysql.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/slave_db1?useUnicode=true&characterEncoding=utf8&useSSL=false&allowMultiQueries=true&serverTimezone=GMT
username: root
password: 123
db2: #从库2
type: com.alibaba.druid.pool.DruidDataSource
driverClassName: com.mysql.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/slave_db2?useUnicode=true&characterEncoding=utf8&useSSL=false&allowMultiQueries=true&serverTimezone=GMT
username: root
password: 123
masterSlaveRule: # 这里配置这个规则的话,相当于是全局读写分离配置
name: ds_rw # 名称,合法的字符串即可,但如果涉及到在读写分离的基础上设置分库分表,则名称需要有意义才可以,另外,虽然目前没有强制要求,但主从库配置需要配置在实际关联的主从库上,如果配置的数据源之间主从是断开的状态,那么可能会发生写入的数据对于只读会话无法读取到的问题
# 如果一个会话发生了写入并且没有提交(显式打开事务),sharidng sphere在后续的路由中,select都会在主库执行,直到会话提交
masterDataSourceName: db0 # 主库的DataSource名称
slaveDataSourceNames: # 从库的DataSource列表,至少需要有一个
- db1
- db2
loadBalanceAlgorithmType: ROUND_ROBIN #从库负载均衡算法类型,可选值:ROUND_ROBIN,RANDOM。若loadBalanceAlgorithmClassName存在则忽略该配置,默认为ROUND_ROBIN
sharding: #指定表的分片规则
tables: # 看到table "s" ,就知道可配置多个
my_table: # 指定表名,此名必须和model中 @TableName(value = "my_table") 一致
actualDataNodes: db$->{0..2}.my_table_$->{0..1} #创建了两个表,下标0和1,所以此处配置你懂的
databaseStrategy:
inline: # 指定表的分片策略
shardingColumn: id #参与分片运算的列名
algorithmExpression: db$->{id % 3} #分片算法,分了三个库,所以要%3
tableStrategy:
inline: # 指定表的分片策略
shardingColumn: id #参与分片运算的列名
algorithmExpression: my_table_$->{id % 2} #分片算法
keyGenerator: # 指定表的主键生成策略
type: SNOWFLAKE #SNOWFLAKE
column: id #指定主键
props:
sql:
show: true #输出日志
一主多从+分库分表
上面实现了一主多从和表分片,现在把它整合到一起
java代码还是没改,主要改的还是Yml
创建了两个主库两个从库master_db1、master_db2、slave_db1、slave_db2
下方配置为 master_db1与slave_db1为主从关系、master_db2与slave_db2为主从关系
修改点有点多,查看标*****的位置
Yml
application-sharding_db_table_masters_slaves.yml
#一主多从+表分片
spring:
application:
name: shardingJdbcDemo
#shardingsphere相关配置
shardingsphere:
datasource:
names: db0,db1,db2,db3 #库名,只是名字 ******************新增名称db3
db0: #主库
type: com.alibaba.druid.pool.DruidDataSource
driverClassName: com.mysql.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/master_db1?useUnicode=true&characterEncoding=utf8&useSSL=false&allowMultiQueries=true&serverTimezone=GMT
username: root
password: 123
db1: #主库1 ****************** 添加主库
type: com.alibaba.druid.pool.DruidDataSource
driverClassName: com.mysql.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/master_db2?useUnicode=true&characterEncoding=utf8&useSSL=false&allowMultiQueries=true&serverTimezone=GMT
username: root
password: 123
db2: #从库1
type: com.alibaba.druid.pool.DruidDataSource
driverClassName: com.mysql.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/slave_db1?useUnicode=true&characterEncoding=utf8&useSSL=false&allowMultiQueries=true&serverTimezone=GMT
username: root
password: 123
db3: #从库2 ******************添加从库
type: com.alibaba.druid.pool.DruidDataSource
driverClassName: com.mysql.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/slave_db2?useUnicode=true&characterEncoding=utf8&useSSL=false&allowMultiQueries=true&serverTimezone=GMT
username: root
password: 123
sharding:
master-slave-rules: # 新增配置 ******************
db0: # 此处名字一定要配置和下面 master-data-source-name 名字一致的
master-data-source-name: db0
slave-data-source-names: db2
db1: # 此处名字一定要配置和下面 master-data-source-name 名字一致的
master-data-source-name: db1
slave-data-source-names: db3
tables: # 看到table "s" ,就知道可配置多个
my_table: # 指定表名,此名必须和model中 @TableName(value = "my_table") 一致
actualDataNodes: db$->{0..1}.my_table_$->{0..1} #******************每组有一主一从,所以是0..1
databaseStrategy:
inline: # 指定表的分片策略
shardingColumn: id #参与分片运算的列名
algorithmExpression: db$->{(id / 10).toBigInteger() % 2} # *******不能再用id%2方式了,会导致数据分配不均,所以需要自定义方法
tableStrategy:
inline: # 指定表的分片策略
shardingColumn: id #参与分片运算的列名
algorithmExpression: my_table_$->{id % 2} #分片算法
keyGenerator: # 指定表的主键生成策略
type: SNOWFLAKE #SNOWFLAKE
column: id #指定主键
props:
sql:
show: true #输出日志
公共表&数据脱敏
公共表
项目中会有很多字典表、配置表等等,此类表数据固定、量级不大,所以可以无需采用分库分表,每个库存一份;
当配置公共表后,每次对公共表进行操作,都会同步操作所有库中的公共表
数据库
分别在三个库中新增表pub_table
Java代码
生成pub_table相关的MybatisPlus代码
Yml
application-publicTable_encryptor.yml
spring:
application:
name: shardingJdbcDemo
#shardingsphere相关配置
shardingsphere:
datasource:
names: db0,db1,db2 #库名,只是名字
db0: #主库
type: com.alibaba.druid.pool.DruidDataSource
driverClassName: com.mysql.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/master_db?useUnicode=true&characterEncoding=utf8&useSSL=false&allowMultiQueries=true&serverTimezone=GMT
username: root
password: 123
db1: #从库1
type: com.alibaba.druid.pool.DruidDataSource
driverClassName: com.mysql.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/slave_db1?useUnicode=true&characterEncoding=utf8&useSSL=false&allowMultiQueries=true&serverTimezone=GMT
username: root
password: 123
db2: #从库2
type: com.alibaba.druid.pool.DruidDataSource
driverClassName: com.mysql.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/slave_db2?useUnicode=true&characterEncoding=utf8&useSSL=false&allowMultiQueries=true&serverTimezone=GMT
username: root
password: 123
sharding:
default-data-source-name: db #如果有多个库,公共表只有一个库有,那么,就要指定有公共表的库,否则会报找不到表
default-database-strategy:
inline:
sharding-column: id
algorithm-expression: db$->{id % 3}
broadcast-tables: pub_table #公共表配置,可以多个
props:
sql:
show: true #输出日志
数据脱敏
spring:
application:
name: shardingJdbcDemo
#shardingsphere相关配置
shardingsphere:
datasource:
names: db #库名,只是名字
db: #数据源
type: com.alibaba.druid.pool.DruidDataSource
driverClassName: com.mysql.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/master_db?useUnicode=true&characterEncoding=utf8&useSSL=false&allowMultiQueries=true&serverTimezone=GMT
username: root
password: 123
sharding: #指定表的分片规则
# 数据脱敏规则配置---start
encrypt-rule:
encryptors:
encryptor_MD5:
type: MD5
props:
md5.key.value: 123456
encryptor_aes:
# 加密、解密器的名字,内置的为MD5,aes.
# 可以自定义,实现
# org.apache.shardingsphere.encrypt.strategy.spi.Encryptor
# 或者
# org.apache.shardingsphere.encrypt.strategy.spi.QueryAssistedEncryptor
# 这两个接口即可
type: aes
props:
aes.key.value: 123456
tables:
# tables
my_table:
columns:
# 逻辑列,就是写SQL里面的列,因为实体类的名字和数据库的加密列一致,所以这里都是name
source:
# 原文列
# plainColumn: password
# 密文列,用来存储密文数据
cipherColumn: source
# 加密器名字
encryptor: encryptor_MD5
# password1:
# 原文列
# plainColumn: password1
# 密文列,用来存储密文数据
# cipherColumn: aes_password
# 加密器名字
# encryptor: encryptor_aes
# 数据脱敏规则配置---end
broadcast-tables: pub_table #公共表
tables: # 看到table "s" ,就知道可配置多个
my_table: # 指定表名,此名必须和model中 @TableName(value = "my_table") 一致
actualDataNodes: db.my_table_$->{0..1} #创建了两个表,下标0和1,所以此处配置你懂的
tableStrategy:
inline: # 指定表的分片策略
shardingColumn: id #参与分片运算的列名
algorithmExpression: my_table_$->{id % 2} #分片算法
keyGenerator: # 指定表的主键生成策略
type: SNOWFLAKE #SNOWFLAKE
column: id #指定主键
props:
sql:
show: true #输出日志
query.with.cipher.column: true #是否使用密文列查询
分布式事务
分库分表后,因为不是一个库了,所以一旦报错,数据无法回滚
Yml
使用上方 application-sharding_db_table_masters_slaves.yml
pom
<!-- 使用 XA 事务时,需要引入此模块 -->
<dependency>
<groupId>io.shardingsphere</groupId>
<artifactId>sharding-transaction-spring-boot-starter</artifactId>
<version>3.1.0</version>
<type>pom</type>
</dependency>
Java
新增
package com.rollback.shardingjdbcdemo.demo.conf;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.sql.DataSource;
@Configuration
@EnableTransactionManagement
public class TransactionConfiguration {
@Bean
public PlatformTransactionManager txManager(final DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
@Bean
public JdbcTemplate jdbcTemplate(final DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
}
修改save方法
saveByTransaction
package com.rollback.shardingjdbcdemo.demo.sharding.controller;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.rollback.shardingjdbcdemo.demo.sharding.model.Table0;
import com.rollback.shardingjdbcdemo.demo.sharding.service.Table0Service;
import org.apache.shardingsphere.api.hint.HintManager;
import org.apache.shardingsphere.transaction.annotation.ShardingTransactionType;
import org.apache.shardingsphere.transaction.core.TransactionType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
import java.util.Random;
/**
* <p>
* 前端控制器
* </p>
*
* @author koala
* @since 2021-05-31
*/
@RestController
@RequestMapping("/table0")
public class Table0Controller {
@Autowired
Table0Service table0Service;
@GetMapping("save")
public void save(int tag){
table0Service.save(new Table0(){{setSource("source"+tag);setRemark("remark"+tag);}});
}
@Transactional
@ShardingTransactionType(TransactionType.XA) // 支持TransactionType.LOCAL, TransactionType.XA, TransactionType.BASE
@GetMapping("saveByTransaction")
public void saveByTransaction(int tag){
for (int i = 0; i < 10; i++) {
if(i==5){
List list=null;
list.add("error");
}
table0Service.save(new Table0(){{setSource("source"+tag);setRemark("remark"+tag);}});
}
}
@GetMapping("select")
public PageInfo select(int pageNum,int pageSize,Long id){
// HintManager hintManager = HintManager.getInstance();
// hintManager.setMasterRouteOnly();
PageHelper.startPage(pageNum,pageSize);
QueryWrapper<Table0> queryWrapper=new QueryWrapper();
if(!StringUtils.isEmpty(id)) {
queryWrapper.eq("id", id);
}
queryWrapper.eq("source","source1");
List<Table0> list = table0Service.list(queryWrapper);
PageInfo pageInfo = new PageInfo<>(list);
return pageInfo;
}
@GetMapping("select1")
public List<Table0> select1(int pageNum,int pageSize,Long id){
QueryWrapper<Table0> queryWrapper=new QueryWrapper();
if(!StringUtils.isEmpty(id)) {
queryWrapper.eq("id", id);
}
//queryWrapper.eq("source","source1");
List<Table0> list = table0Service.list(queryWrapper);
return list;
}
}
验证步骤:
-
清空数据库
-
执行saveByTransaction
-
报错后观察数据库,一条都没有
-
去掉
@Transactional
@ShardingTransactionType(TransactionType.XA) // 支持TransactionType.LOCAL, TransactionType.XA, TransactionType.BASE后,会出现保存部分数据的情况
代码下载
代码见sharding包下,请求入口见 Table0Controller
以上是关于ShardingJdbc-分表;分库分表;读写分离;一主多从+分表;一主多从+分库分表;公共表;数据脱敏;分布式事务的主要内容,如果未能解决你的问题,请参考以下文章
分库分表--- SpringBoot+ShardingSphere实现分表+ 读写分离