最近有個需求,需要區分不同渠道所產生的不同結果。
比如,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