springboot整合shardingjdbc实现简单水平分表

  • Post author:
  • Post category:其他




springboot整合shardingjdbc



1.引入依赖

这里是整合mybatis,都一样,shardingjdbc通过自定义的数据源来拦住你的sql语句进行改写


一定要注意druid数据源

,不能使用自动装配的,要通过shardingjdbc去实例化数据源,那个自动装配会spring去实例化,用了自动装配也可以通过启动类注解排除

@SpringBootApplication(scanBasePackages="com.xxx",exclude={DruidDataSourceAutoConfigure.class})

pom.xml

        <dependency>
            <groupId>org.apache.shardingsphere</groupId>
            <artifactId>sharding-jdbc-spring-boot-starter</artifactId>
            <version>4.1.1</version>
        </dependency>

        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.4</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.20</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.2.6</version>
        </dependency>



2.编写配置文件

两个配置文件 一样的 二选一

application.properties


spring.shardingsphere.datasource.names=ds0

spring.shardingsphere.datasource.ds0.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.ds0.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.ds0.url=jdbc:mysql://127.0.0.1:3308/test_user?characterEncoding=utf8&serverTimezone=UTC&autoReconnect=true&zeroDateTimeBehavior=convertToNull&useSSL=false
spring.shardingsphere.datasource.ds0.username=root
spring.shardingsphere.datasource.ds0.password=root


spring.shardingsphere.sharding.tables.test_user.actual-data-nodes=ds0.test_user_$->{1..2}
spring.shardingsphere.sharding.tables.test_user.table-strategy.standard.sharding-column=id
spring.shardingsphere.sharding.tables.test_user.table-strategy.standard.precise-algorithm-class-name=com.jsu.lzj.config.MyTablePreciseShardingAlgorithm
spring.shardingsphere.sharding.tables.test_user.table-strategy.standard.range-algorithm-class-name=com.jsu.lzj.config.MyTableRangeShardingAlgorithm
spring.shardingsphere.sharding.tables.test_user.key-generator.column=id
spring.shardingsphere.sharding.tables.test_user.key-generator.type=SNOWFLAKE

spring.shardingsphere.props.sql.show = true

mybatis.type-aliases-package=com/jsu/lzj/entity
mybatis.mapper-locations=classpath:mapper/*.xml

application.yml

server:
  port: 8080

spring:
  #  datasource:
  #    url: jdbc:mysql://localhost:3308/test_user?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai
  #    driver-class-name: com.mysql.cj.jdbc.Driver
  #    username: root
  #    password: root

  shardingsphere:
    defaultDataSourceName: ds0
    #配置数据源 可以配置多个 实现分库
    datasource:
      names: ds0
      ds0:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://127.0.0.1:3308/test_user?characterEncoding=utf8&serverTimezone=UTC&autoReconnect=true&zeroDateTimeBehavior=convertToNull&useSSL=false
        username: root
        password: root
    sharding:
      tables:
        # 配置逻辑表和真实表 test_user 逻辑表  ds0上面的数据源 test_user_1 和 test_user_2真实表
        test_user:
          actual-data-nodes: ds0.test_user_$->{1..2}
          #主键生成策略
          key-generator.column: id
          #雪花算法
          key-generator.type: SNOWFLAKE

          #配置分片策略
          table-strategy:
            standard:
              sharding-column: id
              precise-algorithm-class-name: com.jsu.lzj.config.MyTablePreciseShardingAlgorithm
              range-algorithm-class-name: com.jsu.lzj.config.MyTableRangeShardingAlgorithm

#            inline:
#              # 最简洁的分片方式  分片建
#              sharding=column: id
#              # 分片策略 id是integer的  id%2 + 1
#              algorithm-expression: test_user_${id % 2 + 1}
# 打印sql语句
    props:
      sql:
        show: true



3.自定义分片算法 (可以直接用上面的行表达式分片)

自定义精准分片算法

package com.jsu.lzj.config;

import org.apache.shardingsphere.api.sharding.standard.PreciseShardingAlgorithm;
import org.apache.shardingsphere.api.sharding.standard.PreciseShardingValue;

import java.util.Collection;

/**
 * 精准分片策略 作用于 = in 等操作
 * @author lzj
 * @date 2022/3/24
 */
public class MyTablePreciseShardingAlgorithm implements PreciseShardingAlgorithm<Integer> {
    
    @Override
    public String doSharding(Collection<String> collection, PreciseShardingValue<Integer> preciseShardingValue) {
        //获得分片建的id
        Integer value = preciseShardingValue.getValue();
        //根据分片键去取余+1分表
        return "test_user_" + (value % 2 + 1) ;
    }
}

自定义范围分片策略

package com.jsu.lzj.config;

import org.apache.shardingsphere.api.sharding.standard.RangeShardingAlgorithm;
import org.apache.shardingsphere.api.sharding.standard.RangeShardingValue;

import java.util.ArrayList;
import java.util.Collection;

/**
 * 范围分片算法策略 作用于between  > <  >= <=
 * @author lzj
 * @date 2022/3/24
 */
public class MyTableRangeShardingAlgorithm implements RangeShardingAlgorithm<Integer> {
    @Override
    public Collection<String> doSharding(Collection<String> collection, RangeShardingValue<Integer> rangeShardingValue) {
        Collection<String> result = new ArrayList<String>();
        int start = 1;
        int end = collection.size();

        //获取最大值和最小值 没有就会抛出异常 我们捕获他就好
        try{
            start = rangeShardingValue.getValueRange().lowerEndpoint();
        }catch(IllegalStateException e){
            System.out.println("java.lang.IllegalStateException: range unbounded on this side");
        }

        try{
            end = rangeShardingValue.getValueRange().upperEndpoint();
        }catch(IllegalStateException e){
            System.out.println("java.lang.IllegalStateException: range unbounded on this side");
        }

        
        for(int i=start; i <= end; i++){
            //根据范围判断需要查询哪些表
            //collection中包含所有真实表名 我们配置文件中的 ${1..2}  说明有两张
            String tableName =  "test_user_"+ ( i % 2 + 1);
            if(collection.contains(tableName)){
                if(result.contains(tableName)){
                    result.add(tableName);
                }
            }
        }

        return result;
    }
}



4.总结

接下来我们就可以和平常一样写sql去查就行,当我们查询逻辑表的时候,shardingjdbc就会帮我们拦截,根据分片键决定选择哪一张实际表

如果查询条件不包含分片键就会路由到所有表进行查询,最后合并结果

当我们插入不含分片键,也没有在shardingjdbc中配置自动生成策略应该会报错



注意事项


注意那个数据源的地方


注意springboottest

@RunWith(SpringRunner.class)
@SpringBootTest(classes = MySpringBootApplication.class)


分库分表有四种


水平分表:将同样的表格分成多个


垂直分表:将一个表格的不同属性分到多个表格里


水平分库:将同样的表格分成多个到不同数据库


垂直分库:将不同的表格分到不同的数据库,专库专用


shardingjdbc执行流程


sql解析:首先拦截你的sql,然后经过词法分析决定哪些字段需要改写


sql路由:根据分片键决定要路由到哪一些表中


sql改写:将sql逻辑表和其他需要改写的sql字段改写成真实的sql


sql执行:执行sql语句


结果合并:将返回的结果进行合并处理


参考资料:


shardingjdbc官网


分片策略文章解析


参考入门博客



版权声明:本文为xc979906570原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。