ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

分库分表_sharding-jdbc入门demo

2022-06-13 09:05:27  阅读:185  来源: 互联网

标签:分库 demo 数据库 shardingsphere spring sharding order 分片


分库分表

解决问题

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

实现方式:

  • 分库
    • 垂直分库:将表分布到不同的数据库上,每个库可以放在不同服务器上
    • 水平分库:同一表的数据按一定规则拆到不同的数据库中
  • 分表
    • 垂直分表:一个表按照字段分为多个表,拆解原有表结构
    • 水平分表:把同一个表的数据按照一定规则拆到多个表中,解决单表数据量过大的问题

最佳实践:

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

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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有