笔者日常:看朋友发了一篇关于ShardingSphere的文章,我对ShardingSphere挺感兴趣的,于是就学了下。
目录
辅助理解
【分库分表示例】之需求与库表说明
需求说明
需求相关表
【分库分表示例】之代码实现
准备工作
Sharding分片配置
测试一下
测试准备
编写测试方法
进行测试
ShardingSphere功能强大,本文学习使用Sharding-JDBC数据分片功能下的分库分表功能。
注:由于本文知识需要,所以上图做了一个简单说明。
注:本文会涉及到的一些ShardingSphere基础概念,建议先去https://shardingsphere.apa.../sharding/了解一下。
将职工按照不同的年龄段进行分库,按照不同的性别进行分表。具体需求为:age在[0, 50)的,分到younger库;age在[50, 100)的,分到older库;age>=100的,分到other库。其中younger库和older库又按照性别进行分表,男的录入staff_man表,女的录入staff_woman表,other库不区分男女,不论男女都直接录入staff表。
注:本文以实现此需求进行分库分表示例。
上图中的相关表,建表语句为:
CREATE TABLE `staff_man` (
`id` varchar(40) NOT NULL,
`age` int(3) DEFAULT NULL,
`name` varchar(10) DEFAULT NULL,
`gender` char(1) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `staff_woman` (
`id` varchar(40) NOT NULL,
`age` int(3) DEFAULT NULL,
`name` varchar(10) DEFAULT NULL,
`gender` char(1) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `staff` (
`id` varchar(40) NOT NULL,
`age` int(3) DEFAULT NULL,
`name` varchar(10) DEFAULT NULL,
`gender` char(1) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
注:这里先按照需求进行建库建表。
注:建库建表可以使用程序动态创建,不过考虑到本节知识主要讲述ShardingSphere分库分表的实现,就不再引
入其它知识来干扰主题了,所以这里手动创建库表。
软硬件环境说明:Windows10、IntelliJ IDEA、SpringBoot 2.1.4.RELEASE、MySQL、MyBatis。
在pom.xml中引入ShardingSphere分库分表依赖
这里直接给出本人完整的pom.xml:
4.0.0
org.springframework.boot
spring-boot-starter-parent
2.1.4.RELEASE
com.aspire
sharding-database-table
0.0.1-SNAPSHOT
sharding-database-table
分库分表示例
1.8
org.springframework.boot
spring-boot-starter
org.springframework.boot
spring-boot-starter-test
test
org.projectlombok
lombok
true
org.mybatis.spring.boot
mybatis-spring-boot-starter
2.0.0
mysql
mysql-connector-java
8.0.15
com.alibaba
druid
1.1.10
io.shardingjdbc
sharding-jdbc-core
2.0.3
org.springframework.boot
spring-boot-maven-plugin
提示:Sharding分片配置有四种方式
Java配置
Yaml配置
SpringBoot配置
Spring命名空间配置
注:可详见https://shardingsphere.apache.or...onfiguration/。
注:本人这里采用Java配置,是因为Java配置相对于其余三种方式来说,更容易让人理解,但是代价是与代
码耦合度较高。如果比较熟了,推荐使用Yaml配置、SpringBoot配置。
本人Sharding分片配置的相关类说明:
ShardingConfig:核心sharding分片配置类。该类中的主要配置步骤是:
第一步: 获取众多数据源。
第二步: 获取总配置类。
第三步: 获取其余配置信息(如果需要的话)。
第四步:定制指定逻辑表的切片(分库分表)策略。
第五步:将定制了自己的切片策略的表的配置规则,加入总配置中。
第六步:创建并返回sharding总数据源,注入容器。
DatabaseShardingAlgorithm:本人用于数据源分片的算法实现,为ShardingConfig服务。
StaffTableComplexKeysShardingAlgorithm:本人用于逻辑表分片的算法实现,为ShardingConfig服务。
StaffTableTableShardingAlgorithm:本人用于逻辑表分片的算法实现,为ShardingConfig服务。
注:StaffTableComplexKeysShardingAlgorithm和StaffTableTableShardingAlgorithm都是用于对同一个逻辑表
分片的算法实现,在这次的示例项目汇总,其实一个就够了,不过本人这里将两个常用的都进行了实现,
分别实现的是复合分片算法、精准分片算法。
本人Sharding分片配置的相关类的具体代码:
ShardingConfig:
import com.alibaba.druid.pool.DruidDataSource;
import com.aspire.shardingdatabasetable.config.algorithm.DatabaseShardingAlgorithm;
import com.aspire.shardingdatabasetable.config.algorithm.StaffTableComplexKeysShardingAlgorithm;
import com.aspire.shardingdatabasetable.config.algorithm.StaffTableTableShardingAlgorithm;
import io.shardingjdbc.core.api.ShardingDataSourceFactory;
import io.shardingjdbc.core.api.config.ShardingRuleConfiguration;
import io.shardingjdbc.core.api.config.TableRuleConfiguration;
import io.shardingjdbc.core.api.config.strategy.ComplexShardingStrategyConfiguration;
import io.shardingjdbc.core.api.config.strategy.StandardShardingStrategyConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.sql.DataSource;
import java.sql.SQLException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
/**
* 分库分表配置
*
* @author JustryDeng
* @date 2019/5/30 9:54
*/
@Configuration
public class ShardingConfig {
/**
* 切片配置
*
* @return 数据源
* @date 2019/5/30 21:04
*/
@Bean
public DataSource shardingCustomer() throws SQLException {
// 第一步: 获取众多数据源
Map dataSourceMap = getDatasourceMap();
// 第二步: 获取总配置类
ShardingRuleConfiguration shardingRuleConfig = getShardingRuleConfiguration();
// 第三步: 获取其余配置信息(如果需要的话)
Properties properties = getProperties();
// 第四步: 定制指定逻辑表的切片(分库分表)策略
List allTableRuleConfiguration = getAllTableRuleConfiguration();
// 第五步: 将定制了自己的切片策略的表的配置规则,加入总配置中
shardingRuleConfig.getTableRuleConfigs().addAll(allTableRuleConfiguration);
// 第六步: 创建并返回sharding总数据源,注入容器
return ShardingDataSourceFactory.createDataSource(dataSourceMap, shardingRuleConfig,
new ConcurrentHashMap<>(16), properties);
}
/**
* 对指定逻辑表进行切片(分库分表)个性化配置
* 注:本人这里只配置了
*
* @return 定制的 指定表的分库分表配置
* @date 2019/6/4 12:01
*/
private List getAllTableRuleConfiguration() {
List list = new ArrayList<>(8);
// 配置staff表切片规则
TableRuleConfiguration staffTableRuleConfig = new TableRuleConfiguration();
// 逻辑表名
staffTableRuleConfig.setLogicTable("staff");
/*
* 真实库表名
*
* 注:库与表之间使用【.】分割;
* 注:库表与库表之间使用【,】分割
* 下述inline表达式的结果即为 otherDb.staff, youngerDb.staff_man, youngerDb.staff_woman, olderDb.staff_man, olderDb.staff_woman
*/
staffTableRuleConfig.setActualDataNodes("otherDb.staff, ${['youngerDb', 'olderDb']}.staff_${['man', 'woman']}");
// 设置这张表的 分库策略(本人这里采用:标准分片策略)
staffTableRuleConfig.setDatabaseShardingStrategyConfig(
new StandardShardingStrategyConfiguration("age", DatabaseShardingAlgorithm.class.getName()));
// 设置这张表的 分表策略(本人这里采用:精确分片算法实现的标准分片策略)
StandardShardingStrategyConfiguration standardShardingStrategyConfiguration = new StandardShardingStrategyConfiguration(
"gender", StaffTableTableShardingAlgorithm.class.getName(), null);
staffTableRuleConfig.setTableShardingStrategyConfig(standardShardingStrategyConfiguration);
list.add(staffTableRuleConfig);
return list;
}
/**
* 获取其余配置信息
*
* @return 其余配置信息
* @date 2019/6/4 11:24
*/
private Properties getProperties() {
Properties properties = new Properties();
// 打印出分库路由后的sql
properties.setProperty("sql.show", "true");
return properties;
}
/**
* 获取切片总配置类
*
* @return 总配置类
* @date 2019/6/4 11:24
*/
private ShardingRuleConfiguration getShardingRuleConfiguration() {
// sharding总配置类
ShardingRuleConfiguration shardingRuleConfig = new ShardingRuleConfiguration();
// 设置全局默认库
shardingRuleConfig.setDefaultDataSourceName("otherDb");
// 设置全局默认分库的策略(本人这里采用:精确分片算法实现的标准分片策略)
// 如果某个表,没有指定分库策略的话,那么会默认使用这个策略;如果某个表制定了自己的策略,那么就会走自己的策略不走这个默认策略
shardingRuleConfig.setDefaultDatabaseShardingStrategyConfig(
new StandardShardingStrategyConfiguration("age", DatabaseShardingAlgorithm.class.getName()));
// 设置全局默认分表的策略(本人这里采用:复合分片策略)
// 如果某个表,没有指定分表策略的话,那么会默认使用这个策略;如果某个表制定了自己的策略,那么就会走自己的策略不走这个默认策略
ComplexShardingStrategyConfiguration complexShardingStrategyConfiguration = new ComplexShardingStrategyConfiguration(
"age, gender", StaffTableComplexKeysShardingAlgorithm.class.getName());
shardingRuleConfig.setDefaultTableShardingStrategyConfig(complexShardingStrategyConfiguration);
return shardingRuleConfig;
}
/**
* 获取数据源Map
*
* @return 获取数据源Map
* @date 2019/6/4 10:06
*/
private Map getDatasourceMap() {
// 真实数据源map
Map dataSourceMap = new HashMap<>(4);
// 配置第一个数据源,对应库other
DruidDataSource dataSourceDefault = new DruidDataSource();
dataSourceDefault.setDriverClassName("com.mysql.cj.jdbc.Driver");
dataSourceDefault.setUrl("jdbc:mysql://localhost:3306/other?characterEncoding=utf8&serverTimezone=GMT%2B8");
dataSourceDefault.setUsername("root");
dataSourceDefault.setPassword("dengshuai");
dataSourceMap.put("otherDb", dataSourceDefault);
// 配置第二个数据源,对应库younger
DruidDataSource dataSourceYounger = new DruidDataSource();
dataSourceYounger.setDriverClassName("com.mysql.cj.jdbc.Driver");
dataSourceYounger.setUrl("jdbc:mysql://localhost:3306/younger?characterEncoding=utf8&serverTimezone=GMT%2B8");
dataSourceYounger.setUsername("root");
dataSourceYounger.setPassword("dengshuai");
dataSourceMap.put("youngerDb", dataSourceYounger);
// 配置第三个数据源,对应库older
DruidDataSource dataSourceOlder = new DruidDataSource();
dataSourceOlder.setDriverClassName("com.mysql.cj.jdbc.Driver");
dataSourceOlder.setUrl("jdbc:mysql://localhost:3306/older?characterEncoding=utf8&serverTimezone=GMT%2B8");
dataSourceOlder.setUsername("root");
dataSourceOlder.setPassword("dengshuai");
dataSourceMap.put("olderDb", dataSourceOlder);
return dataSourceMap;
}
}
DatabaseShardingAlgorithm:
import io.shardingjdbc.core.api.algorithm.sharding.PreciseShardingValue;
import io.shardingjdbc.core.api.algorithm.sharding.standard.PreciseShardingAlgorithm;
import java.util.Collection;
/**
* 数据源分片策略
*
* 注:本人这里采用的是【精确分片算法PreciseShardingAlgorithm】,类似的算法还有
* 【范围分片算法】
* 【复合分片算法】
* 【Hint分片算法】
*
* @author JustryDeng
* @date 2019/5/31 10:11
*/
public class DatabaseShardingAlgorithm implements PreciseShardingAlgorithm {
/**
* Sharding.
*
* @param availableTargetNames
* 数据源(库)名称集合 或 真实表名称集合。
*
* 提示:数据库源一旦定下来了,那么对应有哪些可用的真实表也就随之定下来了。
*
* 注:这里为: 数据源(库)名称集合。
* 如,本人此次示例中,设置了的数据源有otherDb、youngerDb、olderDb,
* 那么availableTargetNames输出就应为[otherDb, youngerDb, olderDb]
*
* 注:因为是先路由定位库,再路由定位真实表;所以一旦库定下来了,那么真实表的集合就定下来了。
* 以本人的此项目的库与表进行说明:
* otherDb库只有表staff.
* youngerDb库有表staff_man。staff_woman.
* olderDb库有表staff_man。staff_woman.
* 在进行表分片之前会先进性数据库(数据源)分片,在数据源分片时,就路由定下来了走
* otherDb的话,那么这里定位真实表时,候选的真实表集合里只有staff;如果
* 在数据源分片时,路由定下来了走youngerDb的话,那么这里定位真实表时,候选的
* 真实表集合里只有staff_man和staff_woman;
*
* @param shardingValue
* 分片键的值。
* 如:本人此次示例中,要路由到那个数据库源,是由age为数据源分片键的,age的列类型为int,
* 所以这里的泛型是Integer。
* 如果分片键的类型是bigint的话,这里的泛型就应该是Long.
* 如果分片键的类型是varchar/char的话,这里的泛型就应该是String.
*
* @return 路由后的SQL要使用的数据源(库)的名字 或 路由后的SQL要使用的真实表的名字
* 注:这里为: 路由后的SQL要使用的数据源(库)的名字。
*/
@Override
public String doSharding(Collection availableTargetNames,
PreciseShardingValue shardingValue) {
double value = shardingValue.getValue() * 1.0 / 50;
// 年龄在[0, 50)之间的,入youngerDb库
if (value < 1) {
return "youngerDb";
// 年龄在[50, 100)之间的,入olderDb库
} else if (value < 2) {
return "olderDb";
// 年龄在>=100的,入otherDb库
} else {
return "otherDb";
}
/// 注:如果数据源的名称有规律的话(P.S.该名称是我们自己起的,当然可以起得很有规律),
/// 也可以动态将 分片建的值 与 对应 数据源名称关联起来,如
// for (String each : availableTargetNames) {
//
// if (each.endsWith(shardingValue.getValue() % 2 + "")) {
// return each;
// }
// }
// throw new UnsupportedOperationException();
}
}
StaffTableComplexKeysShardingAlgorithm:
import io.shardingjdbc.core.api.algorithm.sharding.ListShardingValue;
import io.shardingjdbc.core.api.algorithm.sharding.ShardingValue;
import io.shardingjdbc.core.api.algorithm.sharding.complex.ComplexKeysShardingAlgorithm;
import java.util.*;
/**
* 自定义符合分片策略
*
* 用于处理使用多键作为分片键进行分片的场景,包含多个分片键的逻辑较复杂,需要应用开发者自行
* 处理其中的复杂度。需要配合ComplexShardingStrategy使用。
*
* @author JustryDeng
* @date 2019/5/31 10:11
*/
public class StaffTableComplexKeysShardingAlgorithm implements ComplexKeysShardingAlgorithm {
/**
* Sharding.
*
* @param availableTargetNames
* 可用的数据源(库)名称集合 或 可用的真实表名称集合。
*
* 提示:数据库源一旦定下来了,那么对应有哪些可用的真实表也就随之定下来了。
*
* 注:这里为: 数据源(库)名称集合。
* 如,本人此次示例中,设置了的数据源有otherDb、youngerDb、olderDb,
* 那么availableTargetNames输出就应为[otherDb, youngerDb, olderDb]
*
* 注:因为是先路由定位库,再路由定位真实表;所以一旦库定下来了,那么真实表的集合就定下来了。
* 以本人的此项目的库与表进行说明:
* otherDb库只有表staff.
* youngerDb库有表staff_man。staff_woman.
* olderDb库有表staff_man。staff_woman.
* 在进行表分片之前会先进性数据库(数据源)分片,在数据源分片时,就路由定下来了走
* otherDb的话,那么这里定位真实表时,候选的真实表集合里只有staff;如果
* 在数据源分片时,路由定下来了走youngerDb的话,那么这里定位真实表时,候选的
* 真实表集合里只有staff_man和staff_woman;
*
* @param shardingValues
* 分片键的值。
* 如:本人此次示例中,要路由到那个数据库源,是由age为数据源分片键的,age的列类型为int,
* 所以这里的泛型是Integer。
* 如果分片键的类型是bigint的话,这里的泛型就应该是Long.
* 如果分片键的类型是varchar/char的话,这里的泛型就应该是String.
* 注: ComplexKeysShardingAlgorithm算法,ShardingValue接口的实现是ListShardingValue。
* 本人这里,shardingValues的toString形如
* shardingValues:[
* ListShardingValue(logicTableName=staff, columnName=age, values=[21]),
* ListShardingValue(logicTableName=staff, columnName=gender, values=[女])
* ]
*
* @return 路由后的SQL要使用的数据源(库)名字的集合 或 路由后的SQL要使用的真实表名字的集合
*/
@Override
public Collection doSharding(Collection availableTargetNames,
Collection shardingValues) {
List list = new ArrayList<>(4);
ListShardingValue listShardingValue;
for (ShardingValue item : shardingValues) {
// 将item拆箱转换为listShardingValue
listShardingValue = (ListShardingValue)item;
System.out.println("逻辑表:" + listShardingValue.getLogicTableName());
System.out.println("列名:" + listShardingValue.getColumnName());
System.out.println("改列的值:" + listShardingValue.getValues());
}
return list;
}
}
StaffTableTableShardingAlgorithm:
import io.shardingjdbc.core.api.algorithm.sharding.PreciseShardingValue;
import io.shardingjdbc.core.api.algorithm.sharding.standard.PreciseShardingAlgorithm;
import java.util.Collection;
/**
* 表分片策略
*
* 提示:PreciseShardingAlgorithm接口的泛型,视对应分片键的数据类型而定
* 如:列是字符串,那么这里是 String
* 列是int,那么这里是 Integer
* 列是bigint,那么这里是 Long
*
* @author JustryDeng
* @date 2019/5/31 10:11
*/
public class StaffTableTableShardingAlgorithm implements PreciseShardingAlgorithm {
/**
* Sharding.
*
* @param availableTargetNames
* 数据源(库)名称集合 或 真实表名称集合。
*
* 提示:数据库源一旦定下来了,那么对应有哪些可用的真实表也就随之定下来了。
*
* 注:这里为: 数据源(库)名称集合。
* 如,本人此次示例中,设置了的数据源有otherDb、youngerDb、olderDb,
* 那么availableTargetNames输出就应为[otherDb, youngerDb, olderDb]
*
* 注:因为是先路由定位库,再路由定位真实表;所以一旦库定下来了,那么真实表的集合就定下来了。
* 以本人的此项目的库与表进行说明:
* otherDb库只有表staff.
* youngerDb库有表staff_man。staff_woman.
* olderDb库有表staff_man。staff_woman.
* 在进行表分片之前会先进性数据库(数据源)分片,在数据源分片时,就路由定下来了走
* otherDb的话,那么这里定位真实表时,候选的真实表集合里只有staff;如果
* 在数据源分片时,路由定下来了走youngerDb的话,那么这里定位真实表时,候选的
* 真实表集合里只有staff_man和staff_woman;
*
* @param shardingValue
* 分片键的值。
* 如:本人此次示例中,路由至哪张表,是由gender为真实表分片键的,
* gender的列类型为char,所以这里的泛型是String。
* 如果分片键的类型是int的话,这里的泛型就应该是Integer.
* 如果分片键的类型是bigint的话,这里的泛型就应该是Long.
* 如果分片键的类型是varchar/char的话,这里的泛型就应该是String.
*
* @return 路由后的SQL要使用的数据源(库)的名字 或 路由后的SQL要使用的真实表的名字
* 注:这里为 路由后的SQL要使用的真实表的名字
*/
@Override
public String doSharding(Collection availableTargetNames,
PreciseShardingValue shardingValue) {
// 根据本人的真实数据节点信息, 如果 可用表里面包含staff,说明一定用的是otherDb数据源,
// 而该数据库里面只有一张表staff, 这里直接返回即可
if (availableTargetNames.contains("staff")) {
return "staff";
}
// 如果是youngerDb数据源 或 olderDb数据源 的话,会走到下面的逻辑
String tmpGender = shardingValue.getValue();
if ("男".equals(tmpGender)) {
return "staff_man";
} else if ("女".equals(tmpGender)) {
return "staff_woman";
}
throw new UnsupportedOperationException();
}
}
StaffPO模型:
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 职工模型, 对应staff表
*
* @author JustryDeng
* @date 2019/6/3 23:26
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class StaffPO {
/** 分布式主键id */
private String id;
/** 年龄 */
private Integer age;
/** 姓名 */
private String name;
/** 性别 */
private String gender;
}
ShardingDatabaseTableApplication启动类:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.transaction.annotation.EnableTransactionManagement;
/**
* 启动类
*
* @author JustryDeng
* @date 2019/5/29 11:03
*/
@SpringBootApplication
@EnableTransactionManagement
public class ShardingDatabaseTableApplication {
public static void main(String[] args) {
SpringApplication.run(ShardingDatabaseTableApplication.class, args);
}
}
ShardingService业务接口:
import com.aspire.shardingdatabasetable.model.StaffPO;
import java.util.List;
/**
* Service层
*
* @author JustryDeng
* @date 2019/5/29 17:35
*/
public interface ShardingService {
/**
* 插入测试
*
* @param staffPO
* 职工模型
* @return 受影响行数
* @date 2019/6/3 23:42
*/
int insertDemo(StaffPO staffPO);
/**
* 查询测试
*
* @param age
* 年龄条件
* @return 满足要求的职工信息集合
* @date 2019/6/4 21:55
*/
List queryDemo(Integer age);
}
ShardingServiceImpl业务实现:
import com.aspire.shardingdatabasetable.mapper.ShardingMapper;
import com.aspire.shardingdatabasetable.model.StaffPO;
import com.aspire.shardingdatabasetable.service.ShardingService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
/**
* 业务逻辑层
*
* @author JustryDeng
* @date 2019/5/29 17:35
*/
@Slf4j
@Service
public class ShardingServiceImpl implements ShardingService {
private final ShardingMapper shardingMapper;
public ShardingServiceImpl(ShardingMapper shardingMapper) {
this.shardingMapper = shardingMapper;
}
@Override
@Transactional(rollbackFor = {Exception.class})
public int insertDemo(StaffPO staffPO) {
log.info("got into ShardingServiceImpl -> insertDemo, param is -> {}", staffPO);
return shardingMapper.insertData(staffPO);
}
@Override
public List queryDemo(Integer age) {
log.info("got into ShardingServiceImpl -> queryDemo, param is -> {}", age);
return shardingMapper.queryStaffByAge(age);
}
}
ShardingMapper数据操作层:
import com.aspire.shardingdatabasetable.model.StaffPO;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import java.util.List;
/**
* 持久层
*
* @author JustryDeng
* @date 2019/5/29 17:36
*/
@Mapper
public interface ShardingMapper {
/**
* 向逻辑表staff中插入数据
*
* @param staffPO
* 职工模型
* @return 受影响行数
* @date 2019/6/3 23:38
*/
@Insert({"insert into staff (`id`, `age`, `name`, `gender`) values (#{staffPO.id},",
" #{staffPO.age}, #{staffPO.name}, #{staffPO.gender})"})
int insertData(@Param("staffPO") StaffPO staffPO);
/**
* 根据年龄大于等于给定age的职工信息
*
* @param age
* 年龄条件
* @return 符合要求的职工集合
* @date 2019/6/4 21:52
*/
@Select("select id, name, age, gender from staff where age >= #{age}")
List queryStaffByAge(Integer age);
}
import com.aspire.shardingdatabasetable.model.StaffPO;
import com.aspire.shardingdatabasetable.service.ShardingService;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.List;
import java.util.UUID;
@RunWith(SpringRunner.class)
@SpringBootTest
public class ShardingDatabaseTableApplicationTests {
@Autowired
ShardingService shardingService;
@Test
public void allTest() {
oneTest();
twoTest();
threeTest();
fourTest();
fiveTest();
sixTest();
}
@Test
public void oneTest() {
String uuid = UUID.randomUUID().toString();
StaffPO staffPO = StaffPO.builder()
.id(uuid)
.name("邓沙利文")
.age(25)
.gender("男")
.build();
int result = shardingService.insertDemo(staffPO);
Assert.assertEquals(1, result);
}
@Test
public void twoTest() {
String uuid = UUID.randomUUID().toString();
StaffPO staffPO = StaffPO.builder()
.id(uuid)
.name("疯一般的女子")
.age(123)
.gender("女")
.build();
int result = shardingService.insertDemo(staffPO);
Assert.assertEquals(1, result);
}
@Test
public void threeTest() {
String uuid = UUID.randomUUID().toString();
StaffPO staffPO = StaffPO.builder()
.id(uuid)
.name("无敌小婷妹")
.age(21)
.gender("女")
.build();
int result = shardingService.insertDemo(staffPO);
Assert.assertEquals(1, result);
}
@Test
public void fourTest() {
String uuid = UUID.randomUUID().toString();
StaffPO staffPO = StaffPO.builder()
.id(uuid)
.name("邓~")
.age(125)
.gender("男")
.build();
int result = shardingService.insertDemo(staffPO);
Assert.assertEquals(1, result);
}
@Test
public void fiveTest() {
String uuid = UUID.randomUUID().toString();
StaffPO staffPO = StaffPO.builder()
.id(uuid)
.name("亨得帅")
.age(66)
.gender("男")
.build();
int result = shardingService.insertDemo(staffPO);
Assert.assertEquals(1, result);
}
@Test
public void sixTest() {
String uuid = UUID.randomUUID().toString();
StaffPO staffPO = StaffPO.builder()
.id(uuid)
.name("小聋女")
.age(80)
.gender("女")
.build();
int result = shardingService.insertDemo(staffPO);
Assert.assertEquals(1, result);
}
@Test
public void qeuryTest() {
List result = shardingService.queryDemo(10);
for (StaffPO staffPO : result) {
System.out.println(staffPO);
}
}
}
插入测试:运行allTest方法后,控制台输出:
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.1.4.RELEASE)
23:56:49.904 [main] INFO Sharding-JDBC-SQL:59- Logic SQL: insert into staff (`id`, `age`, `name`, `gender`) values (?, ?, ?, ?)
23:56:49.906 [main] INFO Sharding-JDBC-SQL:59- SQLStatement: InsertStatement(columns=[Column(name=id, tableName=staff), Column(name=age, tableName=staff), Column(name=name, tableName=staff), Column(name=gender, tableName=staff)], multipleConditions=[], columnsListLastPosition=48, generateKeyColumnIndex=-1, afterValuesPosition=57, valuesListLastPosition=69, generatedKey=null)
23:56:49.906 [main] INFO Sharding-JDBC-SQL:59- Actual SQL: youngerDb ::: insert into staff_man (`id`, `age`, `name`, `gender`) values (?, ?, ?, ?) ::: [2c757252-3779-4d0f-b70f-db272f12b091, 25, 邓沙利文, 男]
23:56:50.116 [main] INFO Sharding-JDBC-SQL:59- Logic SQL: insert into staff (`id`, `age`, `name`, `gender`) values (?, ?, ?, ?)
23:56:50.116 [main] INFO Sharding-JDBC-SQL:59- SQLStatement: InsertStatement(columns=[Column(name=id, tableName=staff), Column(name=age, tableName=staff), Column(name=name, tableName=staff), Column(name=gender, tableName=staff)], multipleConditions=[], columnsListLastPosition=48, generateKeyColumnIndex=-1, afterValuesPosition=57, valuesListLastPosition=69, generatedKey=null)
23:56:50.116 [main] INFO Sharding-JDBC-SQL:59- Actual SQL: otherDb ::: insert into staff (`id`, `age`, `name`, `gender`) values (?, ?, ?, ?) ::: [5a6ed073-5891-482f-ba1e-959f4e832cfd, 123, 疯一般的女子, 女]
23:56:50.149 [main] INFO Sharding-JDBC-SQL:59- Logic SQL: insert into staff (`id`, `age`, `name`, `gender`) values (?, ?, ?, ?)
23:56:50.150 [main] INFO Sharding-JDBC-SQL:59- SQLStatement: InsertStatement(columns=[Column(name=id, tableName=staff), Column(name=age, tableName=staff), Column(name=name, tableName=staff), Column(name=gender, tableName=staff)], multipleConditions=[], columnsListLastPosition=48, generateKeyColumnIndex=-1, afterValuesPosition=57, valuesListLastPosition=69, generatedKey=null)
23:56:50.150 [main] INFO Sharding-JDBC-SQL:59- Actual SQL: youngerDb ::: insert into staff_woman (`id`, `age`, `name`, `gender`) values (?, ?, ?, ?) ::: [3d0aadf3-94e2-4ee8-9715-421fd8f4bc9d, 21, 无敌小婷妹, 女]
23:56:50.208 [main] INFO Sharding-JDBC-SQL:59- Logic SQL: insert into staff (`id`, `age`, `name`, `gender`) values (?, ?, ?, ?)
23:56:50.209 [main] INFO Sharding-JDBC-SQL:59- SQLStatement: InsertStatement(columns=[Column(name=id, tableName=staff), Column(name=age, tableName=staff), Column(name=name, tableName=staff), Column(name=gender, tableName=staff)], multipleConditions=[], columnsListLastPosition=48, generateKeyColumnIndex=-1, afterValuesPosition=57, valuesListLastPosition=69, generatedKey=null)
23:56:50.209 [main] INFO Sharding-JDBC-SQL:59- Actual SQL: otherDb ::: insert into staff (`id`, `age`, `name`, `gender`) values (?, ?, ?, ?) ::: [c1cde34f-3093-4296-ac57-bef30f7b4777, 125, 邓~, 男]
23:56:50.302 [main] INFO Sharding-JDBC-SQL:59- Logic SQL: insert into staff (`id`, `age`, `name`, `gender`) values (?, ?, ?, ?)
23:56:50.302 [main] INFO Sharding-JDBC-SQL:59- SQLStatement: InsertStatement(columns=[Column(name=id, tableName=staff), Column(name=age, tableName=staff), Column(name=name, tableName=staff), Column(name=gender, tableName=staff)], multipleConditions=[], columnsListLastPosition=48, generateKeyColumnIndex=-1, afterValuesPosition=57, valuesListLastPosition=69, generatedKey=null)
23:56:50.302 [main] INFO Sharding-JDBC-SQL:59- Actual SQL: olderDb ::: insert into staff_man (`id`, `age`, `name`, `gender`) values (?, ?, ?, ?) ::: [29c8165f-ba9f-4aad-bb27-552026840ca4, 66, 亨得帅, 男]
23:56:50.374 [main] INFO Sharding-JDBC-SQL:59- Logic SQL: insert into staff (`id`, `age`, `name`, `gender`) values (?, ?, ?, ?)
23:56:50.375 [main] INFO Sharding-JDBC-SQL:59- SQLStatement: InsertStatement(columns=[Column(name=id, tableName=staff), Column(name=age, tableName=staff), Column(name=name, tableName=staff), Column(name=gender, tableName=staff)], multipleConditions=[], columnsListLastPosition=48, generateKeyColumnIndex=-1, afterValuesPosition=57, valuesListLastPosition=69, generatedKey=null)
23:56:50.375 [main] INFO Sharding-JDBC-SQL:59- Actual SQL: olderDb ::: insert into staff_woman (`id`, `age`, `name`, `gender`) values (?, ?, ?, ?) ::: [3f0463a8-26bc-4cf2-8133-7878fda556e0, 80, 小聋女, 女]
打开库表,观察:
older库staff_man表:
older库staff_woman表:
younger库staff_man表:
younger库staff_woman表:
other库staff表:
可见分库分表成功!
查询测试:运行qeuryTest方法后,控制台输出:
查询也没问题!
ShardingSphere实现分库分表完毕!