官方文档: https://shardingsphere.apache.org/document/current/cn/features/sharding/
配置
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-jdbc-spring-boot-starter</artifactId>
<version>4.0.0-RC1</version>
<version>4.0.1</version>
</dependency>
<!-- for spring namespace -->
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-jdbc-spring-namespace</artifactId>
<version>4.0.0-RC1</version>
<version>4.0.1</version>
</dependency>
下面示例是单数据源配置,可以配置多个数据源做主从、分库分表 (可混合使用)。
spring.shardingsphere:
enabled: true
props.sql.show: true
datasource:
names: ds0
ds0:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
jdbc-url: jdbc:mysql://${noob.dburl}?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&failOverReadOnly=false
username: ${noob.dbuser}
password: ${noob.dbpwd}
data-source-properties: #下面子属性只能为小驼峰格式,同使用数据源中的配置属性
maximumPoolSize: ${datasource.maximumPoolSize}
minimumIdle: ${datasource.minimumIdle}
maxLifetime: 300000
connectionTimeout: 30000
idleTimeout: 30000
connectionTestQuery: SELECT 1
sharding.tables:
limit_use:
actual-data-nodes: ds0.limit_use_0$->{0..9},ds0.limit_use_$->{10..31}
table-strategy.complex.sharding-columns: loan_no,contract_no
table-strategy.complex.algorithm-class-name: cn.noob.algorithm.sharding.MurmurConsistentHashFeatureCodeComplexShardingAlgorithm #扩展ComplexKeysShardingAlgorithm混合分片算法
loan:
actual-data-nodes: ds0.loan_0$->{0..9},ds0.loan_$->{10..31}
table-strategy.standard.sharding-column: loan_no
table-strategy.standard.precise-algorithm-class-name: cn.noob.algorithm.sharding.MurmurConsistentHashFeatureCodeShardingAlgorithm #扩展PreciseShardingAlgorithm标准精确分片算法
sharding.bindingTables[0]: limit_use, repayment_plan #綁定表
绑定表
避免多表关联场景产生笛卡尔积结果。
sharding.bindingTables[0]: limit_use, repayment_plan
或者
sharding.bindingTables:
- limit_use, repayment_plan, loan, settle_detail
- customer, bank_account
广播表
所有的分片数据源中都存在的表结构及其数据均完全一致的表, 用于数据量不大且需要与海量数据的表进行关联查询的场景,例如:字典表。
spring.shardingsphere.sharding.broadcast-tables = t_dict
分页解决方式
通常sql语句需要按分表字段过滤,分页不能像常规那样指定分页数查询
- 翻页越往后导致limit 的offset 越来越大,查询效率下降。所以对于后翻太多页的操作直接拒绝(操作意义无效拒绝服务),或许更应该区分冷热数据,历史数据使用其他介质存储: eg. es、hive
- 按降序展示列表:
- “下一页” next:取每页数据最后一条记录的ID - lastId(当前页最小Id,首次查询不用传),取小于它的降序数据集的前 limit 条;
- “上一页” pre: 取每页数据第一条记录的ID - firstId(当前页最大Id), 取大于它的升序数据集的前 limit 条,随后在程序里再对结果集降序排列(Collections.reverse(list);), 以此来保证页面列表数据展示的顺序一致。
<select id="getByPage" resultMap="Contract">
SELECT * FROM contract
<where>
<if test="id != null and id != 0 ">
<choose>
<when test ="opType != null and opType == 'pre' ">
id > #{id}
</when>
<otherwise> id < #{id}</otherwise>
</choose>
</if>
<include refid="dynamicWhere" />
</where>
order by id
<choose>
<when test ="opType != null and opType == 'pre' ">
asc
</when>
<otherwise> desc </otherwise>
</choose>
limit #{pageSize}
</select>
特性
- 支持跨库关联查询,由 Federation 执行引擎提供支持。基于 XA 协议的两阶段事务和基于最终一致性的柔性事务支持
- 有限支持子查询, 子查询一定要有分表键!无论嵌套多少层,ShardingSphere都可以解析至第一个包含数据表的子查询,一旦在下层嵌套中再次找到包含数据表的子查询将直接抛出解析异常。通过子查询进行非功能需求,在大部分情况下是可以支持的,比如分页、统计总数等;而通过子查询实现业务查询当前并不能支持。
- 只能通过sql字面提取用于分片的值,因此当分片键处于运算表达式或函数中时,ShardingSphere无法提前获取分片键位于数据库中的值,从而无法计算出真正的分片值。当出现此类分片键处于运算表达式或函数中的sql时,ShardingSphere将采用全路由的形式获取结果。
-
不能更新分表字段
路由
SELECT i.* FROM t_order o JOIN t_order_item i ON o.order_id=i.order_id WHERE o.order_id in (10, 11);
标准路由
绑定关系表指路由使用相同分片规则的主表和子表。绑定表之间的多表关联查询不会出现笛卡尔积关联,关联查询效率将大大提升。此时走的是标准路由。
在不配置绑定表关系时,假设分片键order_id
将数值10路由至第0片,将数值11路由至第1片,那么路由后的SQL应该为4条,它们呈现为笛卡尔积:
SELECT i.* FROM t_order_0 o JOIN t_order_item_0 i ON o.order_id=i.order_id WHERE o.order_id in (10, 11);
SELECT i.* FROM t_order_0 o JOIN t_order_item_1 i ON o.order_id=i.order_id WHERE o.order_id in (10, 11);
SELECT i.* FROM t_order_1 o JOIN t_order_item_0 i ON o.order_id=i.order_id WHERE o.order_id in (10, 11);
SELECT i.* FROM t_order_1 o JOIN t_order_item_1 i ON o.order_id=i.order_id WHERE o.order_id in (10, 11);
在显式申明配置绑定表关系后,路由的sql应该为2条:
SELECT i.* FROM t_order_0 o JOIN t_order_item_0 i ON o.order_id=i.order_id WHERE o.order_id in (10, 11);
SELECT i.* FROM t_order_1 o JOIN t_order_item_1 i ON o.order_id=i.order_id WHERE o.order_id in (10, 11);
其中t_order
在FROM的最左侧,ShardingSphere将会以它作为整个绑定表的主表。 所有路由计算将会只使用主表的策略,那么t_order_item
表的分片计算将会使用t_order
的条件。故绑定表之间的分区键最好是要相同。
笛卡尔路由
笛卡尔路由是最复杂的情况,它无法根据绑定表的关系定位分片规则,因此非绑定表之间的关联查询需要拆解为笛卡尔积组合执行。 如果上个示例中的SQL并未配置绑定表关系,那么路由的结果应为:
SELECT * FROM t_order_0 o JOIN t_order_item_0 i ON o.order_id=i.order_id WHERE order_id IN (1, 2);
SELECT * FROM t_order_0 o JOIN t_order_item_1 i ON o.order_id=i.order_id WHERE order_id IN (1, 2);
SELECT * FROM t_order_1 o JOIN t_order_item_0 i ON o.order_id=i.order_id WHERE order_id IN (1, 2);
SELECT * FROM t_order_1 o JOIN t_order_item_1 i ON o.order_id=i.order_id WHERE order_id IN (1, 2);
笛卡尔路由查询性能较低,需谨慎使用。
分布式主键
(75条消息) 分布式全局唯一主键_noob_can的博客-CSDN博客https://blog.csdn.net/noob_can/article/details/131548271
支持的分片策略
package org.apache.shardingsphere.core.strategy.route;
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public final class ShardingStrategyFactory {
/**
* @param shardingStrategyConfig sharding strategy configuration
* @return sharding strategy instance
*/
public static ShardingStrategy newInstance(final ShardingStrategyConfiguration shardingStrategyConfig) {
if (shardingStrategyConfig instanceof StandardShardingStrategyConfiguration) {
return new StandardShardingStrategy((StandardShardingStrategyConfiguration) shardingStrategyConfig);
}
if (shardingStrategyConfig instanceof InlineShardingStrategyConfiguration) {
return new InlineShardingStrategy((InlineShardingStrategyConfiguration) shardingStrategyConfig);
}
if (shardingStrategyConfig instanceof ComplexShardingStrategyConfiguration) {
return new ComplexShardingStrategy((ComplexShardingStrategyConfiguration) shardingStrategyConfig);
}
if (shardingStrategyConfig instanceof HintShardingStrategyConfiguration) {
return new HintShardingStrategy((HintShardingStrategyConfiguration) shardingStrategyConfig);
}
return new NoneShardingStrategy();
}
}
-
标准分片StandardShardingStrategy:单一分片键。 精准分片PreciseShardingAlgorithm和范围分片RangeShardingAlgorithm
- 复合分片ComplexShardingStrategy:多个分片键关联逻辑处理ComplexKeysShardingAlgorithm
- Hint分片HintShardingStrategy:指定要查询的分库及分表HintShardingAlgorithm 。配置好使用hint策略的分表及分库算法后,HintManager里设置databaseSharding和tableSharding,使用 ThreadLocal 管理分片键值,仅在当前线程内生效。(还可以通过 SQL 中的特殊注释的方式引用 Hint, 指定了强制分片路由的 SQL 将会无视原有的分片逻辑,直接路由至指定的真实数据节点。)
- 行表达式分片InlineShardingStrategy : 在配置中使用 Groovy 表达式,提供对 SQL语句中的 = 和 IN 的分片操作支持,它只支持单分片键的精准规则。
- 无实际的分片策略NoneShardingStrategy