ShardingSphere
sharding-jdbc-springboot
逻辑表 :水平拆分的数据库(表)的相同逻辑和数据结构表的总称。例:订单数据根据主键尾数拆分为 10 张表,分别是 t_order_0 到 t_order_9,他们的逻辑表名为 t_order。
真实表:数据库中真实存在的物理表。即上个示例中的 t_order_0 到 t_order_9。
数据节点:数据分片的最小单元。由数据源名称和数据表组成,例:ds_0.t_order_0。
绑定表:分片规则一致的主表和子表。例如:t_order 表和 t_order_item 表,均按照 order_id 分片,则此两张表互为绑定表关系。
广播表:指所有的分片数据源中都存在的表,表结构和表中的数据在每个数据库中均完全一致。例如:字典表。
分片键:将数据库(表)水平拆分的关键字段
通过分片算法将数据分片。
StandardShardingAlgorithm:标准分片算法,用于处理使用单一键作为分片键的 =、IN、BETWEEN AND、>、<、>=、<=进行分片的场景。需要配合 StandardShardingStrategy 使用。
ComplexKeysShardingAlgorithm :复合分片算法,用于处理使用多键作为分片键进行分片的场景,包含多个分片键的逻辑较复杂,需要应用开发者自行处理其中的复杂度。需要配合 ComplexShardingStrategy 使用。
HintShardingAlgorithm :Hint分片算法,用于处理使用 Hint 行分片的场景。需要配合 HintShardingStrategy 使用。
包含分片键和分片算法,由于分片算法的独立性,将其独立抽离。真正可用于分片操作的是分片键 + 分片算法,也就是分片策略。目前提供 5 种分片策略。
StandardShardingStrategy:”标准分片策略。提供对 SQ L语句中的 =, >, <, >=, <=, IN 和 BETWEEN AND 的分片操作支持。 StandardShardingStrategy 只支持单分片键,提供 PreciseShardingAlgorithm 和 RangeShardingAlgorithm 两个分片算法。 PreciseShardingAlgorithm 是必选的,用于处理 = 和 IN 的分片。 RangeShardingAlgorithm 是可选的,用于处理 BETWEEN AND, >, <, >=, <=分片,如果不配置 RangeShardingAlgorithm,SQL 中的 BETWEEN AND 将按照全库路由处理。
ComplexShardingStrategy:复合分片策略。提供对 SQL 语句中的 =, >, <, >=, <=, IN 和 BETWEEN AND 的分片操作支持。 ComplexShardingStrategy 支持多分片键,由于多分片键之间的关系复杂,因此并未进行过多的封装,而是直接将分片键值组合以及分片操作符透传至分片算法,完全由应用开发者实现,提供最大的灵活度。
HintShardingStrategy:Hint分片策略,通过 Hint 指定分片值而非从 SQL 中提取分片值的方式进行分片的策略。
NoneShardingStrategy:不分片策略
行表达式的使用非常直观,只需要在配置中使用 ${ expression } 或 $->{ expression } 标识行表达式即可。 目前支持数据节点和分片算法这两个部分的配置。行表达式的内容使用的是 Groovy 的语法,Groovy 能够支持的所有操作,行表达式均能够支持。例如:
${begin…end} 表示范围区间
${[unit1, unit2, unit_x]} 表示枚举值
例如,以下行表达式:
$->{['online', 'offline']}_table$->{1..3}
最终会解析为:
online_table1, online_table2, online_table3, offline_table1, offline_table2, offline_table3
1,引入jar包
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-test
org.projectlombok
lombok
1.18.10
com.github.pagehelper
pagehelper-spring-boot-starter
1.2.12
org.mybatis.spring.boot
mybatis-spring-boot-starter
2.0.1
org.springframework.boot
spring-boot-starter-jdbc
mysql
mysql-connector-java
runtime
org.apache.shardingsphere
sharding-jdbc-spring-boot-starter
4.1.1
io.springfox
springfox-swagger2
2.8.0
io.springfox
springfox-swagger-ui
2.8.0
org.aspectj
aspectjrt
1.8.6
org.aspectj
aspectjweaver
1.8.6
org.springframework.boot
spring-boot-starter-validation
2.2.2.RELEASE
org.apache.commons
commons-lang3
3.11
2,配置
application.yml 文件
server:
port: 8081
spring:
shardingsphere:
props:
sql:
# 打印sql
show: true
orchestration:
registry:
#操作超时的毫秒数,默认500毫秒
operation-timeout-milliseconds: 600000
datasource:
names: ds0,ds0slave,ds1,ds1slave
ds0:
driverClassName: com.mysql.cj.jdbc.Driver
type: com.zaxxer.hikari.HikariDataSource
jdbcUrl: jdbc:mysql://192.168.16.128:3306/ds0?useUnicode=true&characterEncoding=utf-8&autoReconnect=true&serverTimezone=UTC
username: root
password: 123456
# hikari 的线程池配置
maximumPoolSize: 20
minimumIdle: 10
ds0slave:
driverClassName: com.mysql.cj.jdbc.Driver
type: com.zaxxer.hikari.HikariDataSource
jdbcUrl: jdbc:mysql://192.168.16.129:3306/ds0?useUnicode=true&characterEncoding=utf-8&autoReconnect=true&serverTimezone=UTC
username: root
password: 123456
# hikari 的线程池配置
maximumPoolSize: 20
minimumIdle: 10
ds1:
driverClassName: com.mysql.cj.jdbc.Driver
type: com.zaxxer.hikari.HikariDataSource
jdbcUrl: jdbc:mysql://192.168.16.128:3306/ds1?useUnicode=true&characterEncoding=utf-8&autoReconnect=true&serverTimezone=UTC
username: root
password: 123456
# hikari 的线程池配置
maximumPoolSize: 20
minimumIdle: 10
ds1slave:
driverClassName: com.mysql.cj.jdbc.Driver
type: com.zaxxer.hikari.HikariDataSource
jdbcUrl: jdbc:mysql://192.168.16.129:3306/ds1?useUnicode=true&characterEncoding=utf-8&autoReconnect=true&serverTimezone=UTC
username: root
password: 123456
# hikari 的线程池配置
maximumPoolSize: 20
minimumIdle: 10
sharding:
#未分片表的默认数据库
default-data-source-name: ds0
#读写分离
master-slave-rules:
ds0:
master-data-source-name: ds0
slave-data-source-names: ds0slave
ds1:
master-data-source-name: ds1
slave-data-source-names: ds1slave
tables:
#分表案例
users:
actual-data-nodes: ds0.users_$->{0..1}
key-generator:
column: id
type: SNOWFLAKE
table-strategy:
inline:
sharding-column: id
algorithm-expression: users_$->{id % 2}
#分表分库案例
user_pack_records:
actual-data-nodes: ds0.user_pack_records_$->{2018..2019},ds1.user_pack_records_$->{2020..2021}
key-generator:
column: id
type: SNOWFLAKE
database-strategy:
standard:
sharding-column: start_time
precise-algorithm-class-name: com.sharding.jdbc.algorithm.db.UserPackRecordsAlgorithm
range-algorithm-class-name: com.sharding.jdbc.algorithm.db.UserPackRecordsAlgorithm
table-strategy:
standard:
sharding-column: start_time
precise-algorithm-class-name: com.sharding.jdbc.algorithm.table.UserPackRecordsAlgorithm
range-algorithm-class-name: com.sharding.jdbc.algorithm.table.UserPackRecordsAlgorithm
mybatis:
configuration:
#驼峰转化
map-underscore-to-camel-case: true
# Java 与 Mysql 的类型转化基础包
type-handlers-package: com.sharding.jdbc.convert
3,自定义数据库分片算法
import org.apache.shardingsphere.api.sharding.standard.PreciseShardingAlgorithm;
import org.apache.shardingsphere.api.sharding.standard.PreciseShardingValue;
import org.apache.shardingsphere.api.sharding.standard.RangeShardingAlgorithm;
import org.apache.shardingsphere.api.sharding.standard.RangeShardingValue;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
* user_pack_records 分库:阅读时间 start_time 在2018-2019 在 db0,2020-2021 在db1
*/
public class UserPackRecordsAlgorithm implements PreciseShardingAlgorithm<LocalDateTime>, RangeShardingAlgorithm<LocalDateTime> {
/**
* 通过年份获取真实数据库
*
* @param year 年份
* @return 真实数据库
*/
private String getDbByYear(Integer year) {
if (year == 2018 || year == 2019) {
return "ds0";
} else if (year == 2020 || year == 2021) {
return "ds1";
}
throw new IllegalArgumentException();
}
/**
* PreciseShardingAlgorithm 是必选的,用于处理=和IN的分片。
*
* @param availableDbNames 可用的数据库集合
* @param shardingValue 分片键
* @return 真实数据库
*/
@Override
public String doSharding(Collection<String> availableDbNames, PreciseShardingValue<LocalDateTime> shardingValue) {
int year = shardingValue.getValue().getYear();
return getDbByYear(year);
}
/**
* RangeShardingAlgorithm 可选,用于处理BETWEEN AND, >, <, >=, <=分片
*
* @param availableDbNames 可用的数据库集合
* @param rangeShardingValue 分片键
* @return 真实数据库
*/
@Override
public Collection<String> doSharding(Collection<String> availableDbNames, RangeShardingValue<LocalDateTime> rangeShardingValue) {
List<String> dbs = new ArrayList<>();
int lowerYear = rangeShardingValue.getValueRange().lowerEndpoint().toLocalDate().getYear();
LocalDate startDate = LocalDate.of(lowerYear, 1, 1);
LocalDate endDate = rangeShardingValue.getValueRange().upperEndpoint().toLocalDate();
for (LocalDate curDate = startDate; curDate.isBefore(endDate) || curDate.isEqual(endDate); curDate = curDate.plusYears(1)) {
dbs.add(getDbByYear(curDate.getYear()));
}
return dbs;
}
}
自定义分表算法
package com.sharding.jdbc.algorithm.table;
import org.apache.commons.lang3.StringUtils;
import org.apache.shardingsphere.api.sharding.standard.PreciseShardingAlgorithm;
import org.apache.shardingsphere.api.sharding.standard.PreciseShardingValue;
import org.apache.shardingsphere.api.sharding.standard.RangeShardingAlgorithm;
import org.apache.shardingsphere.api.sharding.standard.RangeShardingValue;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
public class UserPackRecordsAlgorithm implements PreciseShardingAlgorithm<LocalDateTime>, RangeShardingAlgorithm<LocalDateTime> {
/**
* 通过年份获取真实表
*
* @param year 年份
* @return 真实表
*/
private String getTableByYear(Collection<String> availableTargetNames, String year) {
for (String targetName : availableTargetNames) {
if (targetName.endsWith(year)) {
return targetName;
}
}
return null;
}
/**
* PreciseShardingAlgorithm 是必选的,用于处理=和IN的分片。
*
* @param availableTargetNames 可用的表集合
* @param shardingValue 分片键
* @return 真实表
*/
@Override
public String doSharding(Collection<String> availableTargetNames, PreciseShardingValue<LocalDateTime> shardingValue) {
LocalDateTime startTime = shardingValue.getValue();
return getTableByYear(availableTargetNames, String.valueOf(startTime.getYear()));
}
/**
* RangeShardingAlgorithm 可选,用于处理BETWEEN AND, >, <, >=, <=分片
*
* @param availableTargetNames 可用的表集合
* @param rangeShardingValue 分片键
* @return 真实表
*/
@Override
public Collection<String> doSharding(Collection<String> availableTargetNames, RangeShardingValue<LocalDateTime> rangeShardingValue) {
List<String> tables = new ArrayList<>();
int lowerYear = rangeShardingValue.getValueRange().lowerEndpoint().toLocalDate().getYear();
LocalDate startDate = LocalDate.of(lowerYear, 1, 1);
LocalDate endDate = rangeShardingValue.getValueRange().upperEndpoint().toLocalDate();
for (LocalDate curDate = startDate; curDate.isBefore(endDate) || curDate.isEqual(endDate); curDate = curDate.plusYears(1)) {
String table = getTableByYear(availableTargetNames, String.valueOf(curDate.getYear()));
if (StringUtils.isNotBlank(table)) {
tables.add(table);
}
}
return tables;
}
}
4,详细代码请进入githut看源代码
sharding-jdbc-springboot