sharding-jdbc配置
一、概念先行
1)SQL相关的
- 逻辑表:水平拆分的数据库(表)的相同逻辑和数据结构表的总称。例:订单数据根据主键尾数拆分为2张表,分别是t_order_0到t_order_1,他们的逻辑表名为t_order。
- 真实表:在分片的数据库中真实存在的物理表。例:示例中的t_order_0到t_order_1
- 数据节点:数据分片的最小单元。由数据源名称和数据表组成,例:ds_0.t_order_0;ds_0.t_order_1;
- 绑定表:指分片规则一致的主表和子表。例如:t_order表和t_order_item表,均按照order_id分片,则此两张表互为绑定表关系。绑定表之间的多表关联查询不会出现笛卡尔积关联,关联查询效率将大大提升。
- 广播表:指所有的分片数据源中都存在的表,表结构和表中的数据在每个数据库中均完全一致。适用于数据量不大且需要与海量数据的表进行关联查询的场景,例如:字典表,示例中的t
2)分片相关
- 分片键:用于分片的数据库字段,是将数据库(表)水平拆分的关键字段。例:将订单表中的订单主键的尾数取模分片,则订单主键为分片字段。 SQL中如果无分片字段,将执行全路由,性能较差。 除了对单分片字段的支持,ShardingSphere也支持根据多个字段进行分片。
- 分片算法:通过分片算法将数据分片,支持通过=、>=、<=、>、<、BETWEEN和IN分片。分片算法需要应用方开发者自行实现,可实现的灵活度非常高。
目前提供4种分片算法:
- 精确分片算法:对应PreciseShardingAlgorithm,用于处理使用单一键作为分片键的=与IN进行分片的场景。需要配合StandardShardingStrategy使用。
- 范围分片算法:对应RangeShardingAlgorithm,用于处理使用单一键作为分片键的BETWEEN AND、>、<、>=、<=进行分片的场景。需要配合StandardShardingStrategy使用。
- 复合分片算法:对应ComplexKeysShardingAlgorithm,用于处理使用多键作为分片键进行分片的场景,包含多个分片键的逻辑较复杂,需要应用开发者自行处理其中的复杂度。需要配合ComplexShardingStrategy使用。
- Hint分片算法:对应HintShardingAlgorithm,用于处理使用Hint行分片的场景。需要配合HintShardingStrategy使用。
- 分片策略:包含分片键和分片算法,由于分片算法的独立性,将其独立抽离。真正可用于分片操作的是分片键 + 分片算法,也就是分片策略。
目前提供5种分片策略。
- 标准分片策略:对应StandardShardingStrategy。提供对SQL语句中的=, >, <, >=, <=, IN和BETWEEN AND的分片操作支持。StandardShardingStrategy只支持单分片键,提供PreciseShardingAlgorithm和RangeShardingAlgorithm两个分片算法。PreciseShardingAlgorithm是必选的,用于处理=和IN的分片。RangeShardingAlgorithm是可选的,用于处理BETWEEN AND, >, <, >=, <=分片,如果不配置RangeShardingAlgorithm,SQL中的BETWEEN AND将按照全库路由处理。
- 复合分片策略:对应ComplexShardingStrategy。复合分片策略。提供对SQL语句中的=, >, <, >=, <=, IN和BETWEEN AND的分片操作支持。ComplexShardingStrategy支持多分片键,由于多分片键之间的关系复杂,因此并未进行过多的封装,而是直接将分片键值组合以及分片操作符透传至分片算法,完全由应用开发者实现,提供最大的灵活度。
- 行表达式分片策略:对应InlineShardingStrategy。使用Groovy的表达式,提供对SQL语句中的=和IN的分片操作支持,只支持单分片键。对于简单的分片算法,可以通过简单的配置使用,从而避免繁琐的Java代码开发,如: t_user_$->{u_id % 8} 表示t_user表根据u_id模8,而分成8张表,表名称为t_user_0到t_user_7。
- Hint分片策略:对应HintShardingStrategy。通过Hint指定分片值而非从SQL中提取分片值的方式进行分片的策略。
- 不分片策略:对应NoneShardingStrategy。不分片的策略。
3)配置相关
- 分片规则:分片规则配置的总入口。包含数据源配置、表配置、绑定表配置以及读写分离配置等。
- 数据源配置:真实数据源列表。
- 表配置:逻辑表名称、数据节点与分表规则的配置
- 数据节点配置:用于配置逻辑表与真实表的映射关系。
- 分片策略配置:
数据源分片策略:对应于DatabaseShardingStrategy。用于配置数据被分配的目标数据源。
表分片策略:对应于TableShardingStrategy。用于配置数据被分配的目标表,该目标表存在与该数据的目标数据源内。故表分片策略是依赖与数据源分片策略的结果的。 - 自增主键生成策略:通过在客户端生成自增主键替换以数据库原生自增主键的方式,做到分布式主键无重复。(雪花算法)
sharding-jdbc配置
sharding: jdbc: datasource: names: ds0 #指定数据源 名称可以自定义,注意:名称要跟后面的配置一致 ds0: #配置数据源的连接信息 type: com.alibaba.druid.pool.DruidDataSource driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://192.168.52.10:3306/ball?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT&useSSL=false&allowPublicKeyRetrieval=true username: root password: Yifan123. config: sharding: props: sql.show: true #是否输出sql tables: sys_role: #逻辑表名 key-generator-column-name: id #主键 #分库分表数据节点 # actual-data-nodes: ds$->{0..2}.t_order$->{0..1} # 数据节点:多数据源$->{0..N}.逻辑表名$->{0..N}相同表 # actual-data-nodes: ds0.t_order$->{0..1},ds1.t_order$->{2..4} # 数据节点:多数据源$->{0..N}.逻辑表名$->{0..N}不同表 # actual-data-nodes: ds0.t_order$->{0..4} # 指定单数据源的配置方式 # actual-data-nodes: ds0.t_order0,ds1.t_order0,ds0.t_order1,ds1.t_order1 # 全部手动指定 actual-data-nodes: ds0.sys_role${0..1} #数据节点,均匀分布 #数据源分片策略 # database-strategy: # inline: #行表达式 # sharding-column: id #按照指定列进行分库---分库策略使用ID字段取模 # algorithm-expression: ds$->{user_id%2} #按模运算分配 #分表策略 table-strategy:
#标准分片算法
standard:
sharding-column: id
# 精确分片算法,用于 = 和 IN。该类需实现 PreciseShardingAlgorithm 接口并提供无参数的构造器
precise-algorithm-class-name: com.chain.utils.MyPreciseShardingAlgorithm
# 范围分片算法类名称,用于 范围查询 可选。该类需实现 RangeShardingAlgorithm 接口并提供无参数的构造器
range-algorithm-class-name: com.chain.utils.MyRangeShardingAlgorithm # inline: #行表达式 # sharding-column: id #按照指定列进行分表---分表策略使用ID字段取模 # algorithm-expression: sys_role${id % 2} #按模运算分配
ShardingJDBC提供了5种分片策略及分片算法
一、标准分片策略 StandardShardingStrategyConfiguration
支持单个分片键,提供对SQL语句中的=, IN和BETWEEN AND的分片操作支持
1. 精确分片算法 MyPreciseShardingAlgorithm(必选)

/** * 精确匹配查询,需要实现PreciseShardingAlgorithm,可以实现对 `=`以及`in`的查询 */ public class MyPreciseShardingAlgorithm implements PreciseShardingAlgorithm<Long> { /** * 精确匹配查询 * * @param tbNames 数据库中所有的事实表 * @param shardingValue 分片相关信息 * @return 返回匹配的数据源 */ @Override public String doSharding(Collection<String> tbNames, PreciseShardingValue<Long> shardingValue) { for (String tableName : tbNames) { /* * shardingValue.getValue() 为分片建的值,比如 id=2时,value就是 2 * 比如:表分为user_1到user_6,id=1操作user_1表,id=6操作user_6表 * * `+ 6`的目的是为了保证,id=6操作user_6表,运维6%6=0,需要再进行`+6` */ long index = shardingValue.getValue() % tbNames.size(); //String value = String.valueOf(index == 0 ? index + 6 : index); // 匹配满足当前分片规则的表名称 if (tableName.endsWith(String.valueOf(index))) { return tableName; } } throw new RuntimeException("数据库不存在"); } }
2. 范围分片算法 MyRangeShardingAlgorithm(非必选,不配置则全库路由处理)

public class MyRangeShardingAlgorithm implements RangeShardingAlgorithm<Long> { @Override public Collection<String> doSharding(Collection<String> tbNames, RangeShardingValue<Long> rangeShardingValue) { // 获取逻辑表名称 String logicTableName = rangeShardingValue.getLogicTableName(); // between and 的起始值,需要处理只有最大值或者只有最小值的情况 boolean hasLowerBound = rangeShardingValue.getValueRange().hasLowerBound(); boolean hasUpperBound = rangeShardingValue.getValueRange().hasUpperBound(); // 只有最小值,比如:id > x if (hasLowerBound && !hasUpperBound) { // 直接返回所有表名称 return tbNames; } // 只有最大值,比如:id < x if (!hasLowerBound && hasUpperBound) { long upper = rangeShardingValue.getValueRange().upperEndpoint(); if (upper < tbNames.size()) { // 如果最大值小于表的总数,则返回需要的表名 return matchMinAndMax(1, upper, logicTableName, tbNames); } else { // 如果最大值大于表的总数,则返回所有 return tbNames; } } long lower = Long.valueOf(rangeShardingValue.getValueRange().lowerEndpoint()); long upper = Long.valueOf(rangeShardingValue.getValueRange().upperEndpoint()); // 拼接事实表名称 return matchMinAndMax(lower, upper, logicTableName, tbNames); } private List<String> matchMinAndMax(long lower, long upper, String logicTableName, Collection<String> tbNames) { List<String> tableNameList = new ArrayList<>(); for (long index = lower; index <= upper; index++) { long tableNum = index % tbNames.size(); // 事实表后缀 //String suffix = String.valueOf(tableNum == 0 ? tableNum + 6 : tableNum); String tableName = logicTableName + tableNum; if (tbNames.contains(tableName)) { // 添加满足要求的表名称 tableNameList.add(tableName); } // 如果满足要求的表已经覆盖了所有表,此处处理是为了方式查询区间过大,而分表不多,导致的过度遍历 if (tableNameList.size() == tbNames.size()) { return tableNameList; } } return tableNameList; } }
二、复合分片策略 ComplexShardingStrategyConfiguration
支持多个分片键,提供对SQL语句中的=, IN和BETWEEN AND的分片操作支持。
三、Inline表达式分片策略 InlineShardingStrategyConfiguration
使用Groovy的Inline表达式,提供对SQL语句中的=和IN的分片操作支持
四、Hint分片策略 HintShardingStrategyConfiguration
通过Hint而非SQL解析的方式分片的策略
五、不分片的策略 NoneShardingStrategyConfiguration