分库分表_sharding-jdbc入门demo
作者:互联网
分库分表
解决问题:
由于数据量过大而导致数据库性能降低的问题
实现方式:
- 分库
- 垂直分库:将表分布到不同的数据库上,每个库可以放在不同服务器上
- 水平分库:同一表的数据按一定规则拆到不同的数据库中
- 分表
- 垂直分表:一个表按照字段分为多个表,拆解原有表结构
- 水平分表:把同一个表的数据按照一定规则拆到多个表中,解决单表数据量过大的问题
最佳实践:
系统设计阶段根据业务耦合松紧来确定垂直分库、垂直分表方案,数据访问量不大的情况下,首先考虑缓存、读写分离、索引技术等方案。若数据量极大,再考虑水平分库和水平分表方案(带来的开发和维护成本较高)
sharding-jdbc
数据分片的主要流程:
SQL解析——>执行器优化——>SQL路由——>SQL改写——>SQL执行——>结果归并
实现数据分片的四种策略:
- inline模式:表达式分片策略:db${0..1}.t_order{0..1}
- standard模式:标准分片策略
- complex模式:用于多分片键的复合分片策略
- Hint模式:强制分片策略
Inner模式实现水平分表
- 配置数据源
- 配置物理节点
- 配置数据库的分片策略
- 配置表的分片策略
order_db_1
├── t_order_1
└── t_order_2
└── t_dict
order_db_2
├── t_order_1
└── t_order_2
└── t_dict
# 1. 配置数据源
# 数据源名称,多数据源以逗号分隔
spring.shardingsphere.datasource.names=ds1,ds2
# 数据库连接池类名称
spring.shardingsphere.datasource.ds1.type=com.alibaba.druid.pool.DruidDataSource
# 数据库驱动类名
spring.shardingsphere.datasource.ds1.driver-class-name=com.mysql.cj.jdbc.Driver
# 数据库 url 连接
spring.shardingsphere.datasource.ds1.url=jdbc:mysql://192.168.200.129:3306/order_db_1?serverTimezone=GMT%2B8
# 数据库用户名
spring.shardingsphere.datasource.ds1.username=root
# 数据库密码
spring.shardingsphere.datasource.ds1.password=root
#sharding.jdbc.datasource.<data-source-name>.xxx= # 数据库连接池的其它属性
# 数据库连接池类名称
spring.shardingsphere.datasource.ds2.type=com.alibaba.druid.pool.DruidDataSource
# 数据库驱动类
spring.shardingsphere.datasource.ds2.driver-class-name=com.mysql.cj.jdbc.Driver
# 数据库 url 连
spring.shardingsphere.datasource.ds2.url=jdbc:mysql://192.168.200.129:3306/order_db_2?serverTimezone=GMT%2B8
# 数据库用户
spring.shardingsphere.datasource.ds2.username=root
# 数据库密
spring.shardingsphere.datasource.ds2.password=root
# 2. 配置物理节点
# 由数据源名 + 表名组成,以小数点分隔。多个表以逗号分隔,支持 inline 表达式。\
# 缺省表示使用已知数据源与逻辑表名称生成数据节点。用于广播表(即每个库中都需要一个同样的表用于关联查询,多为字典表)\
# 或只分库不分表且所有库的表结构完全一致的情况
spring.shardingsphere.sharding.tables.t_order.actual-data-nodes=ds${1..2}.t_order_${1..2}
#3. 配置数据库的分片策略
spring.shardingsphere.sharding.tables.t_order.database-strategy.inline.sharding-column=user_id
# 分片算法行表达式,需符合 groovy 语法
spring.shardingsphere.sharding.tables.t_order.database-strategy.inline.algorithm-expression=ds${user_id % 2+1}
#4. 配置表的分片策略
# 行表达式分片策略
# 分片列名称
spring.shardingsphere.sharding.tables.t_order.table-strategy.inline.sharding-column=order_id
# 分片算法行表达式,需符合 groovy 语法
spring.shardingsphere.sharding.tables.t_order.table-strategy.inline.algorithm-expression=t_order_${order_id % 2+1}
#配置广播表 # 广播表规则列表
spring.shardingsphere.sharding.broadcast-tables=t_dict
# 打印逻辑SQL和物理SQL
# 是否开启 SQL 显示,默认值: false
spring.shardingsphere.props.sql.show=true
Standard模式实现分库分表
配置
# 1. 配置数据源
# 数据源名称,多数据源以逗号分隔
spring.shardingsphere.datasource.names=ds1,ds2
# 数据库连接池类名称
spring.shardingsphere.datasource.ds1.type=com.alibaba.druid.pool.DruidDataSource
# 数据库驱动类名
spring.shardingsphere.datasource.ds1.driver-class-name=com.mysql.cj.jdbc.Driver
# 数据库 url 连接
spring.shardingsphere.datasource.ds1.url=jdbc:mysql://192.168.200.129:3306/order_db_1?serverTimezone=GMT%2B8
# 数据库用户名
spring.shardingsphere.datasource.ds1.username=root
# 数据库密码
spring.shardingsphere.datasource.ds1.password=root
#sharding.jdbc.datasource.<data-source-name>.xxx= # 数据库连接池的其它属性
# 数据库连接池类名称
spring.shardingsphere.datasource.ds2.type=com.alibaba.druid.pool.DruidDataSource
# 数据库驱动类
spring.shardingsphere.datasource.ds2.driver-class-name=com.mysql.cj.jdbc.Driver
# 数据库 url 连
spring.shardingsphere.datasource.ds2.url=jdbc:mysql://192.168.200.129:3306/order_db_2?serverTimezone=GMT%2B8
# 数据库用户
spring.shardingsphere.datasource.ds2.username=root
# 数据库密
spring.shardingsphere.datasource.ds2.password=root
# 2. 配置物理节点
# 由数据源名 + 表名组成,以小数点分隔。多个表以逗号分隔,支持 inline 表达式。\
# 缺省表示使用已知数据源与逻辑表名称生成数据节点。用于广播表(即每个库中都需要一个同样的表用于关联查询,多为字典表)\
# 或只分库不分表且所有库的表结构完全一致的情况
spring.shardingsphere.sharding.tables.t_order.actual-data-nodes=ds${1..2}.t_order_${1..2}
#3. 配置数据库的分片策略
spring.shardingsphere.sharding.tables.t_order.database-strategy.standard.sharding-column=user_id
# 精确分片算法类名称,用于 = 和 IN。该类需实现 PreciseShardingAlgorithm 接口并提供无参数的构造器
spring.shardingsphere.sharding.tables.t_order.database-strategy.standard.precise-algorithm-class-name=com.itheima.sharding.algorithm.PreciseShardingAlgorithm4Db
# 范围分片算法类名称,用于 BETWEEN,可选。该类需实现 RangeShardingAlgorithm 接口并提供无参数的构造器
spring.shardingsphere.sharding.tables.t_order.database-strategy.standard.range-algorithm-class-name=com.itheima.sharding.algorithm.RangeShardingAlgorithm4Db
#4. 配置表的分片策略
spring.shardingsphere.sharding.tables.t_order.table-strategy.standard.sharding-column=order_id
# 精确分片算法类名称,用于 = 和 IN。该类需实现 PreciseShardingAlgorithm 接口并提供无参数的构造器
spring.shardingsphere.sharding.tables.t_order.table-strategy.standard.precise-algorithm-class-name=com.itheima.sharding.algorithm.PreciseShardingAlgorithm4Tb
# 范围分片算法类名称,用于 BETWEEN,可选。该类需实现 RangeShardingAlgorithm 接口并提供无参数的构造器
spring.shardingsphere.sharding.tables.t_order.table-strategy.standard.range-algorithm-class-name=com.itheima.sharding.algorithm.RangeShardingAlgorithm4Tb
#配置广播表 # 广播表规则列表
spring.shardingsphere.sharding.broadcast-tables=t_dict
# 打印逻辑SQL和物理SQL
# 是否开启 SQL 显示,默认值: false
spring.shardingsphere.props.sql.show=true
精准查询库
package com.it.sharding.algorithm;
import org.apache.shardingsphere.api.sharding.standard.PreciseShardingAlgorithm;
import org.apache.shardingsphere.api.sharding.standard.PreciseShardingValue;
import java.util.Collection;
//定义精准查询数据库的算法类,接口中的泛型与数据库中的片键类型一致
public class PreciseShardingAlgorithm4Db implements PreciseShardingAlgorithm<Long> {
@Override
public String doSharding(Collection<String> dsNames, PreciseShardingValue<Long> shardingValue) {
//获取数据库的分片名称 user_id
String columnName = shardingValue.getColumnName();
//获取逻辑表名称
String logicTableName = shardingValue.getLogicTableName();
//获取片键对应的值
Long value = shardingValue.getValue();
//一般是根据片键值获取对应数据源 并返回
String sufix = String.valueOf(value % 2 + 1);
String dsName = dsNames.stream().filter(ds -> ds.endsWith(sufix)).findFirst().get();
return dsName;
}
}
范围查询库
package com.it.sharding.algorithm;
import com.google.common.collect.Range;
import org.apache.shardingsphere.api.sharding.standard.RangeShardingAlgorithm;
import org.apache.shardingsphere.api.sharding.standard.RangeShardingValue;
import java.util.Arrays;
import java.util.Collection;
//定义范围查询时匹配数据库的算法,对于精准查询,只返回一个库——String;对于范围查询,匹配多个库,返回为Collection
public class RangeShardingAlgorithm4Db implements RangeShardingAlgorithm<Long> {
@Override
public Collection<String> doSharding(Collection<String> dsNames, RangeShardingValue<Long> shardingValue) {
//获取分片字段
String columnName = shardingValue.getColumnName();
//获取逻辑表
String logicTableName = shardingValue.getLogicTableName();
//获取范围数据
Range<Long> valueRange = shardingValue.getValueRange();
//判断是否有上限值
if (valueRange.hasUpperBound()) {
Long upper = valueRange.upperEndpoint();
System.out.println("upper = " + upper);
}
if (valueRange.hasLowerBound()) {
Long lower = valueRange.lowerEndpoint();
System.out.println("lower = " + lower);
}
//根据上下限获取满足条件的数据源集合
return Arrays.asList("ds1","ds2");
}
}
精准表查询
package com.it.sharding.algorithm;
import org.apache.shardingsphere.api.sharding.standard.PreciseShardingAlgorithm;
import org.apache.shardingsphere.api.sharding.standard.PreciseShardingValue;
import java.util.Collection;
/**
* @author
* @Date 2022/6/11
* @Description 定义精准查询表的算法类 接口中的泛型与数据库的片键类型一致
* 保证片键中使用= in
*/
public class PreciseShardingAlgorithm4Tb implements PreciseShardingAlgorithm<Long> {
/**
* 定义精准匹配表的方法
* @param tbNames 所有配置的物理表的集合t_order_${1..2} 包含t_order_1 t_order_2封装到该集合下
* 说白了就是sharinding把所有的数据源都给你,然后让你根据片键值选择
* @param shardingValue 封装分片相关信息
* @return 返回匹配的数据源
*/
@Override
public String doSharding(Collection<String> tbNames, PreciseShardingValue<Long> shardingValue) {
//获取数据库分片的字段名称 user_id = in
String columnName = shardingValue.getColumnName();
//获取逻辑表名称
String logicTableName = shardingValue.getLogicTableName();
//获取片键对应的值 select * from t_order where order_id=10,这里的value就等于10
Long value = shardingValue.getValue();
//一般是根据片键值获取对应的数据源,并返回
String sufix=String.valueOf(value % 2 +1);
String dsName = tbNames.stream().filter(ds -> ds.endsWith(sufix)).findFirst().get();
return dsName;
}
}
范围表查询
package com.it.sharding.algorithm;
import com.google.common.collect.Range;
import org.apache.shardingsphere.api.sharding.standard.RangeShardingAlgorithm;
import org.apache.shardingsphere.api.sharding.standard.RangeShardingValue;
import java.util.Arrays;
import java.util.Collection;
/**
* @author
* @Date 2022/6/11
* @Description 定义范围查询时匹配表的算法
* 对应精准查询,只匹配一个库 --》string
* 对应范围查询来说,可能需要匹配多个库,才能获取数据--》Collection<String>
* 保证片键使用between and
*/
public class RangeShardingAlgorithm4Tb implements RangeShardingAlgorithm<Long> {
/**
*
* @param tbNames 数据源集合
* @param shardingValue 范围查询信息封装
* @return
*/
@Override
public Collection<String> doSharding(Collection<String> tbNames, RangeShardingValue<Long> shardingValue) {
//获取分片字段
String columnName = shardingValue.getColumnName();
//获取逻辑表
String logicTableName = shardingValue.getLogicTableName();
//获取范围数据
Range<Long> valueRange = shardingValue.getValueRange();
//select * from t_order where user_id between 1 and 20;
//判断是否有上限值
if (valueRange.hasUpperBound()) {
//获取上限值 20
Long uppper = valueRange.upperEndpoint();
System.out.println(uppper);
}
if (valueRange.hasLowerBound()){
Long lower = valueRange.lowerEndpoint();
System.out.println(lower);
}
//理论上要根据上限值和下限值获取满足条件的数据源集合
return Arrays.asList("t_order_1","t_order_2");
}
}
标签:分库,demo,数据库,shardingsphere,spring,sharding,order,分片 来源: https://www.cnblogs.com/albert-liu/p/16369517.html