qinfengge

qinfengge

醉后不知天在水,满船清梦压星河
github

好用到爆的sharding-jdbc分库分表组件

最近有个需求,需要区分不同渠道所产生的不同结果。
比如,web 端产生的结果,小程序产生的结果,app 产生的结果。实际上表结构是完全相同的,只是做不同的区分。

在体验之后,如果不是大项目,或者分库分表的重要性很高,不推荐用 shareding jdbc。
这玩意问题太多了,文档还少,坑很多。
简单的小项目直接用 mybatis-plus 的动态表名插件即可

分表#

首先想到的当然是分表,大部分分表是基于数据量的分表,因为众所周知的 MySQL 数据库的单表瓶颈。
300W Mysql 可以轻松抗住
600W 数据开始卡,优化可以解决(表结构,索引设计)
800W ~ 1000W 牛逼的 DBA 优化都会遇到瓶颈

而现在的需求是基于业务的分表,所有要自己设置分表的逻辑了。

sharding-jdbc#

要说分库分表就绕不开 SHARDING-JDBC 这个组件。
它定位为轻量级 Java 框架,在 Java 的 JDBC 层提供的额外服务。它使用客户端直连数据库,以 jar 包形式提供服务,无需二额外部署和依赖,可理解为增强版的 JDBC 驱动,完全兼容 JDBC 和各种 ORM 框架。
  Sharding-JDBC 的核心功能为数据分片和读写分离,通过 Sharding-JDBC,应用可以透明的使用 jdbc 访问已经分库分表、读写分离的多个数据源,而不用关心数据源的数量以及数据如何分布。

安装依赖#

要使用 Sharding-JDBC,首先要做 pom 文件中添加依赖

        <!-- druid -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.22</version>
        </dependency>
        <!--mysql驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
            <version>8.0.23</version>
        </dependency>
        <!--mybatis-plus-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.3.1</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.3</version>
        </dependency>
        <!-- sharding-jdbc 分库分表依赖-->
        <dependency>
            <groupId>org.apache.shardingsphere</groupId>
            <artifactId>sharding-jdbc-spring-boot-starter</artifactId>
            <version>4.1.1</version>
        </dependency>

需要注意的是,如果使用了 druid,依赖必须使用 druid,而不能是 druid-spring-boot-starter。issues

配置文件#

安装完成后需要在配置文件中声明分库分表的配置及规则

#需要加入下面的配值允许重载bean名称,主要用于后面sql对表的操作,MybatisPlus是根据类名作为表名的
spring.main.allow-bean-definition-overriding=true

#分片策略,多个数据源则用逗号隔开,例如: ds0,ds1
spring.shardingsphere.datasource.names=ds0

#配置数据源内容,下面的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://localhost:3306/jk_test?useUnicode=true&characterEncoding=utf-8&autoReconnect=true&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true&allowPublicKeyRetrieval=true&useSSL=false&serverTimezone=GMT%2B8
spring.shardingsphere.datasource.ds0.username=root
spring.shardingsphere.datasource.ds0.password=root

#表的位置 在那个数据源(数据库),那个表。 下面的tables.inspection_result中的inspection_result是表名以什么开头
#配置分表指定的哪些表,这里指定了inspection_result和inspection_result_home 2张表
spring.shardingsphere.sharding.tables.inspection_result.actual-data-nodes=ds0.inspection_result, ds0.inspection_result_home

#指定inspection_result表里面主键cid的生成策略  SNOWFLAKE是雪花算法
#spring.shardingsphere.sharding.tables.course.key-generator.column=cid
#spring.shardingsphere.sharding.tables.course.key-generator.type=SNOWFLAKE

#表的分片策略
spring.shardingsphere.sharding.tables.inspection_result.table-strategy.standard.sharding-column=id
#基于业务分表,此处就是自定义的分表策略
spring.shardingsphere.sharding.tables.inspection_result.table-strategy.standard.precise-algorithm-class-name=com.jkkj.config.ResultPreciseShardingAlgorithm

#打开sql输出日志
spring.shardingsphere.props.sql.show=true

自定义分表策略#

可以使用自定义的分表策略来实现业务需求

public class ResultPreciseShardingAlgorithm implements PreciseShardingAlgorithm<Long> {
    @Override
    public String doSharding(Collection<String> collection, PreciseShardingValue<Long> preciseShardingValue) {
        Long id = preciseShardingValue.getValue();
        if (id < 8000000) {
            return "inspection_result";
        } else {
            return "inspection_result_home";
        }
    }
}

根据 id 判断返回的表名即可

范围分片#

我们使用的 strategy.standard.precise 表示的是标准分片策略,它用来提供对 SQL 语句中的 =, IN 的分片操作支持。

思考一下,现在的分片策略是根据 id 大小进行的,如果要查询某个范围内的数据,能不能成功呢?
答案是不能。标准分片不支持范围查询,但可以使用范围分片。

#表的分片策略
spring.shardingsphere.sharding.tables.inspection_result.table-strategy.standard.sharding-column=id
#基于业务分表,此处就是自定义的分表策略
# standard.precise-algorithm 标准策略下分片算法包含2个 precise + range,range是可选的,但是如果使用 range 就必须同 precise 配套一起使用
# 精确分片算法类名称,用于=和IN
spring.shardingsphere.sharding.tables.inspection_result.table-strategy.standard.precise-algorithm-class-name=com.jkkj.config.ResultPreciseShardingAlgorithm
# 范围分片算法类名称,用于BETWEEN,并使其支持<,<=,>,>=
spring.shardingsphere.sharding.tables.inspection_result.table-strategy.standard.range-algorithm-class-name=com.jkkj.config.ResultPreciseShardingAlgorithm

有了范围分片的算法,也要有范围分片的策略
可以看到,范围分片和标准分片使用的是同一个 ResultPreciseShardingAlgorithm实现类
所有要重新修改下分表策略,新增范围分片

public class ResultPreciseShardingAlgorithm implements PreciseShardingAlgorithm<Integer>, RangeShardingAlgorithm<Integer> {

    @Override
    public String doSharding(Collection<String> collection, PreciseShardingValue<Integer> preciseShardingValue) {
        try {
            Integer id = preciseShardingValue.getValue();
            if (id < 8000000) {
                return "inspection_result";
            } else {
                return "inspection_result_home";
            }
        } catch (NumberFormatException e) {
            log.error("在分表时id转换异常");
            throw new RuntimeException(e);
        }
    }

    @Override
    public Collection<String> doSharding(Collection<String> collection, RangeShardingValue<Integer> rangeShardingValue) {
        Range<Integer> valueRange = rangeShardingValue.getValueRange();
//        Integer lowerEndpoint = valueRange.lowerEndpoint();
//        Integer upperEndpoint = valueRange.upperEndpoint();

        log.info("range : {}", valueRange);

        Collection<String> tables = new ArrayList<>();

        if (Range.closed(0, 8000000).encloses(valueRange)) {
            tables.add("inspection_result");
        } else {
            tables.add("inspection_result_home");
        }
        log.info("tables: {}", tables);
        return collection;
    }
}

完成分表#

其它的业务逻辑不需要修改,在查 inspection_result 表时,Sharding-JDBC 会自动的查询 2 张表并组合。

ShardingSphere
Sharding-jdbc 的实战入门之水平分表(一)
Sharding-JDBC 快速入门(只水平分表)
Sharding-JDBC: 单库分表的实现
Sharding-JDBC 快速入门
shardingsphere 启动的时候报错 Property ‘sqlSessionFactory‘ or ‘sqlSessionTemplate‘ are required
Sharding-JDBC 之 RangeShardingAlgorithm(范围分片算法)
Sharding JDBC (四) 分片策略一:标准分片策略 StandardShardingStrategy

Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.