sharding-jdbc 兼容 MybatisPlus動(dòng)態(tài)數(shù)據(jù)源的配置方法
背景:之前的項(xiàng)目做讀寫分離的時(shí)候用的 MybatisPlus的動(dòng)態(tài)數(shù)據(jù)做的,很多地方使用的@DS直接指定的讀庫(kù)或者寫庫(kù)實(shí)現(xiàn)的業(yè)務(wù);隨著表數(shù)據(jù)量越來(lái)越大,現(xiàn)在打算把比較大的表進(jìn)行水平拆分,準(zhǔn)備使用 ShardingJDBC實(shí)現(xiàn),但是發(fā)現(xiàn)兩者配合起來(lái)并不是那么順利,網(wǎng)上大部分文章都是直接把整個(gè)Sharding的數(shù)據(jù)源當(dāng)成MybatisPlus的一個(gè)數(shù)據(jù)源,那么在原本@DS上面指定的數(shù)據(jù)源就無(wú)法直接使用Sharding的分庫(kù)等邏輯,所以我研究了一下源碼,實(shí)現(xiàn)了這一邏輯,給后面有需要的朋友提供一個(gè)案例,避免浪費(fèi)不必要的時(shí)間
一. 版本選擇
目前ShardingJDBC主要有兩個(gè)版本,一個(gè)是ShardingJDBC早期版本,一個(gè)是ShardingSphere項(xiàng)目中的ShardingSphere-JDBC
- Sharding-JDBC:Sharding-JDBC 最初由當(dāng)時(shí)的項(xiàng)目發(fā)起人在2016年發(fā)布。它最早作為一個(gè)輕量級(jí)的 JDBC 層解決方案,旨在解決數(shù)據(jù)庫(kù)分片和讀寫分離的問(wèn)題。
- ShardingSphere:ShardingSphere 項(xiàng)目是由 Sharding-JDBC 項(xiàng)目發(fā)展而來(lái)的,并在2018年正式發(fā)布。Apache ShardingSphere 致力于構(gòu)建更為完整的分布式數(shù)據(jù)庫(kù)管理生態(tài)系統(tǒng),包含了 Sharding-JDBC、Sharding-Proxy 和 Sharding-Sidecar等多個(gè)組件。
目前獨(dú)立的ShardingJDBC已經(jīng)停更,使用到的最多的版本是 4.1.1
<dependency> <groupId>org.apache.shardingsphere</groupId> <artifactId>sharding-jdbc-spring-boot-starter</artifactId> <version>4.1.1</version> </dependency>
ShardingSphere項(xiàng)目目前一直處于更新迭代中,ShardingSphere-JDBC 是通過(guò)ShardingJDBC 更新迭代過(guò)來(lái)的,在原有代碼的基礎(chǔ)進(jìn)行了一些優(yōu)化和新功能加入,對(duì)于開發(fā)者而言,主要是參數(shù)的配置發(fā)生了一些調(diào)整。但是參數(shù)的作用和配置方式和以前一樣;
這里我為了方便以后會(huì)使用到新特性,我直接使用的是 ShardingSphere-JDBC 5.2.1
官方幫助文檔:https://www.bookstack.cn/read/shardingsphere-5.1.0-zh/ecf18b21ab3f559c.md
<dependency> <groupId>org.apache.shardingsphere</groupId> <artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId> <version>5.2.1</version> </dependency>
二. 項(xiàng)目依賴
案例全部的 Maven依賴如下:
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <dependency> <groupId>com.zaxxer</groupId> <artifactId>HikariCP</artifactId> <version>3.4.5</version> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.4.0</version> </dependency> <!-- 讀寫分離 --> <dependency> <groupId>com.baomidou</groupId> <artifactId>dynamic-datasource-spring-boot-starter</artifactId> <version>3.3.2</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.33</version> </dependency> <!--Shardingjdbc--> <dependency> <groupId>org.apache.shardingsphere</groupId> <artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId> <version>5.2.1</version> <exclusions> <exclusion> <groupId>org.yaml</groupId> <artifactId>snakeyaml</artifactId> </exclusion> </exclusions> </dependency> <!-- 添加正確版本的 SnakeYAML shardingsphere-jdbc里面的依賴版本有問(wèn)題,會(huì)報(bào)錯(cuò)--> <dependency> <groupId>org.yaml</groupId> <artifactId>snakeyaml</artifactId> <version>1.33</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies>
三. 參數(shù)配置
application.yml 配置
server: port: 8080 mybatis-plus: mapper-locations: classpath*:mybatis/*.xml type-aliases-package: com.game.sharding.dto configuration: map-underscore-to-camel-case: false log-impl: org.apache.ibatis.logging.stdout.StdOutImpl spring: application: name: sharding-jdbc-test sharding-sphere: datasource: names: master,write,read,read2 master: type: com.zaxxer.hikari.HikariDataSource driver-class-name: com.mysql.cj.jdbc.Driver jdbc-url: jdbc:mysql://127.0.0.1:3306/game_dev?characterEncoding=utf-8&useSSL=false&allowMultiQueries=true&autoReconnect=true&serverTimezone=Asia/Shanghai username: root password: 123456 write: type: com.zaxxer.hikari.HikariDataSource driver-class-name: com.mysql.cj.jdbc.Driver jdbc-url: jdbc:mysql://127.0.0.1:3306/game_dev?characterEncoding=utf-8&useSSL=false&allowMultiQueries=true&autoReconnect=true&serverTimezone=Asia/Shanghai username: root password: 123456 read: type: com.zaxxer.hikari.HikariDataSource driver-class-name: com.mysql.cj.jdbc.Driver jdbc-url: jdbc:mysql://127.0.0.1:3306/game_dev_read?characterEncoding=utf-8&useSSL=false&allowMultiQueries=true&autoReconnect=true&serverTimezone=Asia/Shanghai username: root password: 123456 read2: type: com.zaxxer.hikari.HikariDataSource driver-class-name: com.mysql.cj.jdbc.Driver jdbc-url: jdbc:mysql://127.0.0.1:3306/game_dev_read?characterEncoding=utf-8&useSSL=false&allowMultiQueries=true&autoReconnect=true&serverTimezone=Asia/Shanghai username: root password: 123456 rules: sharding: tables: team_msg: ## 這里的customer-ds是下面配置的讀寫分離的數(shù)據(jù)源名稱 actual-data-nodes: customer-ds.team_msg_${0..1} table-strategy: standard: sharding-column: id sharding-algorithm-name: msg-id # 對(duì)應(yīng)下面的sharding-algorithms sharding-algorithms: ## 注意這里名稱(例如msg-id)不能用下劃線,會(huì)加載不了下面的參數(shù)導(dǎo)致啟動(dòng)報(bào)錯(cuò) msg-id: type: INLINE props: ## 使用id取模算法 algorithm-expression: team_msg_${id % 2} ## 讀寫分離相關(guān) readwrite-splitting: data-sources: customer-ds: load-balancer-name: customer-lb static-strategy: write-data-source-name: master read-data-source-names: read,read2,write load-balancers: customer-lb: ## 使用自定義的復(fù)雜均衡算法 type: CUSTOM props: # 顯示處理之后的真實(shí)sql sql-show: true
四. 代碼配置
最關(guān)鍵的配置就是需要把MybatisPlus的數(shù)據(jù)源注冊(cè)為使用 shardingsphere-jdbc 的數(shù)據(jù)源,并且保證數(shù)據(jù)源的名稱和原來(lái)MybatisPlus的數(shù)據(jù)源一致,shardingSphereDataSource里面其實(shí)有一個(gè)Map保存了application.yml中所有配置的數(shù)據(jù)源,這里主要是為了方便后續(xù)使用@DS做動(dòng)態(tài)數(shù)據(jù)源切換,所以把同一個(gè)ShardingSphere的數(shù)據(jù)庫(kù)注冊(cè)為4個(gè)動(dòng)態(tài)數(shù)據(jù)源,避免使用@DS找不到對(duì)應(yīng)的數(shù)據(jù)源;
import com.baomidou.dynamic.datasource.DynamicRoutingDataSource; import com.baomidou.dynamic.datasource.provider.AbstractDataSourceProvider; import com.baomidou.dynamic.datasource.provider.DynamicDataSourceProvider; import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceAutoConfiguration; import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceProperties; import org.apache.commons.lang3.StringUtils; import org.apache.shardingsphere.driver.jdbc.adapter.AbstractDataSourceAdapter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.SpringBootConfiguration; import org.springframework.boot.autoconfigure.AutoConfigureBefore; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Primary; import javax.annotation.Resource; import javax.sql.DataSource; import java.util.Arrays; import java.util.HashMap; import java.util.Map; @Configuration @AutoConfigureBefore({DynamicDataSourceAutoConfiguration.class, SpringBootConfiguration.class}) public class MyDataSourceConfiguration { /** * mybatisplus 動(dòng)態(tài)數(shù)據(jù)源配置項(xiàng) */ @Autowired private DynamicDataSourceProperties properties; /** * shardingjdbc的數(shù)據(jù)源 */ @Lazy @Resource(name = "shardingSphereDataSource") private AbstractDataSourceAdapter shardingSphereDataSource; @Value("${spring.sharding-sphere.datasource.names}") private String shardingDataSourceNames; /** * 注冊(cè)動(dòng)態(tài)數(shù)據(jù)源 這里非常關(guān)鍵,因?yàn)槲覀冃枰玫紷DS注解配置動(dòng)態(tài)選擇數(shù)據(jù)源,同上又要讓選擇的數(shù)據(jù)源使用shardingjdbc的數(shù)據(jù)源 * 所以,這里需要?jiǎng)討B(tài)的把所有的數(shù)據(jù)源都注冊(cè)為 shardingjdbc的數(shù)據(jù)源 */ @Bean public DynamicDataSourceProvider dynamicDataSourceProvider() { if (StringUtils.isBlank(shardingDataSourceNames)) { throw new RuntimeException("配置 spring.sharding-sphere.datasource.names 不能為空"); } String[] names = shardingDataSourceNames.split(","); return new AbstractDataSourceProvider() { @Override public Map<String, DataSource> loadDataSources() { Map<String, DataSource> dataSourceMap = new HashMap<>(); Arrays.stream(names).forEach(name -> dataSourceMap.put(name, shardingSphereDataSource)); return dataSourceMap; } }; } /** * 將動(dòng)態(tài)數(shù)據(jù)源設(shè)置為首選數(shù)據(jù)源 */ @Primary @Bean public DataSource dataSource(DynamicDataSourceProvider dynamicDataSourceProvider) { DynamicRoutingDataSource dataSource = new DynamicRoutingDataSource(); dataSource.setPrimary(properties.getPrimary()); dataSource.setStrict(properties.getStrict()); dataSource.setStrategy(properties.getStrategy()); dataSource.setProvider(dynamicDataSourceProvider); dataSource.setP6spy(properties.getP6spy()); dataSource.setSeata(properties.getSeata()); return dataSource; } }
五. 自定義ShardingSphere中的復(fù)雜均衡算法
shardingsphere中的負(fù)載均衡需要實(shí)現(xiàn)ReadQueryLoadBalanceAlgorithm接口并在getType方法中返回自定義的算法名稱,官方自帶的又RoundRobinReadQueryLoadBalanceAlgorithm,RandomReadQueryLoadBalanceAlgorithm等,這里我們必須自定義算法才能兼容@DS注解實(shí)現(xiàn)自由切換數(shù)據(jù)源;
ShardingSphere使用的是SPI機(jī)制加載的,對(duì)應(yīng)的加載源碼部分如下:
所以如果我們要讓自定義的ReadQueryLoadBalanceAlgorithm類生效,需要在項(xiàng)目中的 META-INF的services文件夾中創(chuàng)建org.apache.shardingsphere.readwritesplitting.spi.ReadQueryLoadBalanceAlgorithm 文件,并且把自定義的類填入該文件中
源碼中的配置如下:
那么我們按照源碼的配置直接在自己的項(xiàng)目中創(chuàng)建即可
最后自定義的CustomLoadBalanceAlgorithm 實(shí)現(xiàn)
public class CustomLoadBalanceAlgorithm implements ReadQueryLoadBalanceAlgorithm { private Properties props; public CustomLoadBalanceAlgorithm() { } @Override public void init(Properties props) { this.props = props; } /** * 獲取數(shù)據(jù)源 * * @param name 數(shù)據(jù)源名稱(ShardingJDBC使用的) * @param writeDataSourceName 寫數(shù)據(jù)源名稱 * @param readDataSourceNames 所有配置的復(fù)雜均衡中讀數(shù)據(jù)源名稱 * @param context 事務(wù)上下文對(duì)象,可以獲取context.isInTransaction() 判斷是否需要事務(wù),可通過(guò)這個(gè)來(lái)判斷是否使用 寫數(shù)據(jù)源 * @return java.lang.String */ @Override public String getDataSource(String name, String writeDataSourceName, List<String> readDataSourceNames, TransactionConnectionContext context) { // 獲取當(dāng)前MybatisPlus指定的數(shù)據(jù)源 String dsKey = DynamicDataSourceContextHolder.peek(); if (StringUtils.isNotBlank(dsKey)) { if (writeDataSourceName.equals(dsKey)) { return dsKey; } if (readDataSourceNames.contains(dsKey)) { return dsKey; } throw new RuntimeException("@DS 配置錯(cuò)誤,當(dāng)前數(shù)據(jù)源[" + dsKey + "]不在SharingJDBC數(shù)據(jù)源列表[" + readDataSourceNames + "]中"); } return writeDataSourceName; } @Override public String getType() { return "CUSTOM"; } @Override public boolean isDefault() { return true; } @Override @Generated public Properties getProps() { return this.props; } }
那么此時(shí)你的ShardingSphere就已經(jīng)完全適配之前MybatisPlus動(dòng)態(tài)數(shù)據(jù)源了
六. 源碼
Gitee: https://gitee.com/luowenjie98/sharing-sphere-mybatisplus-demo
到此這篇關(guān)于sharding-jdbc 兼容 MybatisPlus的動(dòng)態(tài)數(shù)據(jù)源的文章就介紹到這了,更多相關(guān)sharding-jdbc MybatisPlus的動(dòng)態(tài)數(shù)據(jù)源內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot?項(xiàng)目打成?jar后加載外部配置文件的操作方法
這篇文章主要介紹了SpringBoot?項(xiàng)目打成?jar后加載外部配置文件的操作方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-03-03Spring?Retry?實(shí)現(xiàn)樂(lè)觀鎖重試實(shí)踐記錄
本文介紹了在秒殺商品SKU表中使用樂(lè)觀鎖和MybatisPlus配置樂(lè)觀鎖的方法,并分析了測(cè)試環(huán)境和生產(chǎn)環(huán)境的隔離級(jí)別對(duì)樂(lè)觀鎖的影響,通過(guò)簡(jiǎn)單驗(yàn)證,展示了在可重復(fù)讀和讀已提交隔離級(jí)別下的不同行為,感興趣的朋友一起看看吧2025-03-03JVM參數(shù)NativeMemoryTracking的使用
本文主要介紹了JVM參數(shù)NativeMemoryTracking的使用,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2025-01-01springBoot中的CORS跨域注解@CrossOrigin詳解
這篇文章主要介紹了springBoot中的CORS跨域注解@CrossOrigin詳解,通常,服務(wù)于?JS?的主機(jī)(例如?example.com)與服務(wù)于數(shù)據(jù)的主機(jī)(例如?api.example.com)是不同的,在這種情況下,CORS?可以實(shí)現(xiàn)跨域通信,需要的朋友可以參考下2023-12-12