其他分享
首页 > 其他分享> > 分库分表_sharding-jdbc入门demo

分库分表_sharding-jdbc入门demo

作者:互联网

分库分表

解决问题

由于数据量过大而导致数据库性能降低的问题

实现方式:

最佳实践:

系统设计阶段根据业务耦合松紧来确定垂直分库、垂直分表方案,数据访问量不大的情况下,首先考虑缓存、读写分离、索引技术等方案。若数据量极大,再考虑水平分库和水平分表方案(带来的开发和维护成本较高)

sharding-jdbc

数据分片的主要流程:

SQL解析——>执行器优化——>SQL路由——>SQL改写——>SQL执行——>结果归并

实现数据分片的四种策略:

  1. inline模式:表达式分片策略:db${0..1}.t_order{0..1}
  2. standard模式:标准分片策略
  3. complex模式:用于多分片键的复合分片策略
  4. Hint模式:强制分片策略

官方文档

Inner模式实现水平分表

  1. 配置数据源
  2. 配置物理节点
  3. 配置数据库的分片策略
  4. 配置表的分片策略
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