qinfengge

qinfengge

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

好用到爆的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

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。