SpringBoot集成Sharding-JDBC實(shí)現(xiàn)分庫(kù)分表方式
一、環(huán)境搭建
1.創(chuàng)建一個(gè)springboot項(xiàng)目,引入以下依賴。
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.1.20</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>org.apache.shardingsphere</groupId> <artifactId>sharding-jdbc-spring-boot-starter</artifactId> <version>4.0.0-RC1</version> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.0.5</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> </dependencies>
2.創(chuàng)建一個(gè)數(shù)據(jù)庫(kù)user和兩張表user_1,user_2
CREATE DATABASE `user`; CREATE TABLE `user_1` ( `id` bigint(30) NOT NULL, `username` varchar(255) DEFAULT NULL, `password` varchar(255) DEFAULT NULL, `gender` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 CREATE TABLE `user_2` ( `id` bigint(30) NOT NULL, `username` varchar(255) DEFAULT NULL, `password` varchar(255) DEFAULT NULL, `gender` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8

3.分別創(chuàng)建user表對(duì)應(yīng)的實(shí)體類和mapper
實(shí)體類代碼
@Data
public class User {
private Long id;
private String username;
private String password;
private String gender;
}
mapper代碼
public interface UserMapper extends BaseMapper<User>{
}結(jié)構(gòu)圖:

二、實(shí)現(xiàn)水平分表
需求:現(xiàn)在有兩個(gè)user表,一個(gè)是user_1,一個(gè)是user_2,當(dāng)id為偶數(shù)的時(shí)候向user_1表中插入數(shù)據(jù),當(dāng)id為奇數(shù)的時(shí)候向user_2表中插入數(shù)據(jù),實(shí)現(xiàn)水平分表。
1.配置application.properties
#指定當(dāng)前應(yīng)用的所有數(shù)據(jù)源標(biāo)識(shí)(由于后期可能會(huì)涉及到多個(gè)數(shù)據(jù)源,或讀寫分離等,這里要為每個(gè)數(shù)據(jù)源
# 起一個(gè)標(biāo)識(shí)名,然后為每個(gè)數(shù)據(jù)源具體配置)
spring.shardingsphere.datasource.names=d1
#配置d1這個(gè)數(shù)據(jù)源,由于這里是水平分表,所以只需要一個(gè)數(shù)據(jù)源即可 其中d1代表該數(shù)據(jù)源的一個(gè)標(biāo)識(shí)
spring.shardingsphere.datasource.d1.type=com.alibaba.druid.pool.DruidDataSource
#指定鏈接驅(qū)動(dòng)
spring.shardingsphere.datasource.d1.driver-class-name=com.mysql.cj.jdbc.Driver
#指定鏈接url
spring.shardingsphere.datasource.d1.url=jdbc:mysql://localhost:3308/user?useSSL=false&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC
#指定鏈接用戶名
spring.shardingsphere.datasource.d1.username=root
#指定鏈接密碼
spring.shardingsphere.datasource.d1.password=root
#由于是水平分表,所以會(huì)涉及到多張相同的表,這里指定這些表的分布情況:在哪個(gè)數(shù)據(jù)源上,以及一共有幾張表
#指定在d1數(shù)據(jù)源,且有user_1和user_2兩張表
#$->{1..2}該表達(dá)式是與前面的user_相拼接的,不能亂寫,例如我們現(xiàn)在的兩張表名是user_1和user_2,那這里就是user_$->{1..2}
#如果我們分布了3張表 user_5,user_6,user_7,那這里就是user_$->{5..6..7}
spring.shardingsphere.sharding.tables.user.actual-data-nodes=d1.user_$->{1..2}
# 指定 user 表里面主鍵id 以及id的生成策略 SNOWFLAKE:表示用雪花算法生成該id
spring.shardingsphere.sharding.tables.user.key-generator.column=id
spring.shardingsphere.sharding.tables.user.key-generator.type=SNOWFLAKE
# 指定分片策略 約定 id 值偶數(shù)添加到 user_1 表,如果 id 是奇數(shù)添加到 user_2表
#指定要根據(jù)哪個(gè)字段進(jìn)行分表,這里根據(jù)id進(jìn)行分表
spring.shardingsphere.sharding.tables.user.table-strategy.inline.sharding-column=id
#執(zhí)行分表的規(guī)則:注意這里是$->{id% 2 + 1},由于偶數(shù)%2的結(jié)果為0,但是我們并沒有user_0這樣表
#所以我們要在取模的結(jié)果上+1 這樣就實(shí)現(xiàn)了如果是偶數(shù)那么取模的結(jié)果就是user_1,如果是奇數(shù)就是user_2
spring.shardingsphere.sharding.tables.user.table-strategy.inline.algorithm-expression=user_$->{id% 2 + 1}
#開啟sql 輸出日志
spring.shardingsphere.props.sql.show=true
# 由于一個(gè)實(shí)體類對(duì)應(yīng)兩張表,所以會(huì)產(chǎn)生覆蓋操作,加上這個(gè)配置解決覆蓋問題
spring.main.allow-bean-definition-overriding=true
2.編寫測(cè)試代碼
@Test
void testAddUser() {
for (int i = 0;i < 6;i++){
User user = new User();
user.setGender("0");
user.setPassword(UUID.randomUUID().toString().substring(0,5));
user.setUsername("-->" + i);
userMapper.insert(user);
}
}
3.日志查看:

可以看到當(dāng)user_id的值為偶數(shù)的時(shí)候,是向user_1表中插入的。

再看當(dāng)user_id的值為奇數(shù)的時(shí)候,該條數(shù)據(jù)插入了user_2這個(gè)表。
三、實(shí)現(xiàn)水平分庫(kù)
需求:現(xiàn)在有兩個(gè)user庫(kù),一個(gè)是user_db1,一個(gè)是user_db2,每個(gè)user庫(kù)中都有兩張相同的表,user_1,user_2,當(dāng)user對(duì)象的gender屬性值為1的時(shí)候向user_db1庫(kù)中插入,當(dāng)user對(duì)象的gender屬性值為0的時(shí)候向user_db2庫(kù)中插入,這是分庫(kù)的規(guī)則,分表的規(guī)則是,當(dāng)id為偶數(shù)的時(shí)候向user_1表中插入數(shù)據(jù),當(dāng)id為奇數(shù)的時(shí)候向user_2表中插入數(shù)據(jù)。(建表語(yǔ)句和上面是相同的)
結(jié)構(gòu)如下:

2.配置application.properties
#指定當(dāng)前應(yīng)用的所有數(shù)據(jù)源標(biāo)識(shí)(由于后期可能會(huì)涉及到多個(gè)數(shù)據(jù)源,或讀寫分離等,這里要為每個(gè)數(shù)據(jù)源
# 起一個(gè)標(biāo)識(shí)名,然后為每個(gè)數(shù)據(jù)源具體配置)
spring.shardingsphere.datasource.names=d1,d2
#配置d1這個(gè)數(shù)據(jù)源,由于這里是水平分表,所以只需要一個(gè)數(shù)據(jù)源即可 其中d1代表該數(shù)據(jù)源的一個(gè)標(biāo)識(shí)
spring.shardingsphere.datasource.d1.type=com.alibaba.druid.pool.DruidDataSource
#指定鏈接驅(qū)動(dòng)
spring.shardingsphere.datasource.d1.driver-class-name=com.mysql.cj.jdbc.Driver
#指定鏈接url
spring.shardingsphere.datasource.d1.url=jdbc:mysql://localhost:3308/user_db1?useSSL=false&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC
#指定鏈接用戶名
spring.shardingsphere.datasource.d1.username=root
#指定鏈接密碼
spring.shardingsphere.datasource.d1.password=root
#由于是兩個(gè)數(shù)據(jù)庫(kù),所以要配置兩個(gè)數(shù)據(jù)源
#配置d2數(shù)據(jù)源
spring.shardingsphere.datasource.d2.type=com.alibaba.druid.pool.DruidDataSource
#指定鏈接驅(qū)動(dòng)
spring.shardingsphere.datasource.d2.driver-class-name=com.mysql.cj.jdbc.Driver
#指定鏈接url
spring.shardingsphere.datasource.d2.url=jdbc:mysql://localhost:3308/user_db2?useSSL=false&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC
#指定鏈接用戶名
spring.shardingsphere.datasource.d2.username=root
#指定鏈接密碼
spring.shardingsphere.datasource.d2.password=root
#指定數(shù)據(jù)庫(kù)和表的分布情況
#指定數(shù)據(jù)庫(kù)分布情況,數(shù)據(jù)庫(kù)里面表分布情況
#d$->{1..2}.user_$->{1..2} 表示在d1,d2數(shù)據(jù)源上都有user_1和user_2兩張表
spring.shardingsphere.sharding.tables.user.actual-data-nodes=d$->{1..2}.user_$->{1..2}
# 指定 user 表里面主鍵id 以及id的生成策略 SNOWFLAKE:表示用雪花算法生成該id
spring.shardingsphere.sharding.tables.user.key-generator.column=id
spring.shardingsphere.sharding.tables.user.key-generator.type=SNOWFLAKE
# 指定分片策略 約定 id 值偶數(shù)添加到 user_1 表,如果 id 是奇數(shù)添加到 user_2表
#指定要根據(jù)哪個(gè)字段進(jìn)行分表,這里根據(jù)id進(jìn)行分表
spring.shardingsphere.sharding.tables.user.table-strategy.inline.sharding-column=id
#執(zhí)行分表的規(guī)則:注意這里是$->{id% 2 + 1},由于偶數(shù)%2的結(jié)果為0,但是我們并沒有user_0這樣表
#所以我們要在取模的結(jié)果上+1 這樣就實(shí)現(xiàn)了如果是偶數(shù)那么取模的結(jié)果就是user_1,如果是奇數(shù)就是user_2
spring.shardingsphere.sharding.tables.user.table-strategy.inline.algorithm-expression=user_$->{id% 2 + 1}
#============================================================================================
#以上指定了分表策略,下面指定分庫(kù)策略,也就是gender為0則向user_db1中插入,為1則向user_db2中插入
spring.shardingsphere.sharding.tables.user.database-strategy.inline..sharding-column=gender
#如果gender為0 則表達(dá)式{gender=='0'?1:2}的結(jié)果就是1,則d$->{gender=='0'?1:2} = d1,就會(huì)向d1數(shù)據(jù)源也就是user_db1庫(kù)中添加
#如果gender為1 則表達(dá)式{gender=='0'?1:2}的結(jié)果就是2,則d$->{gender=='0'?1:2} = d2,就會(huì)向d1數(shù)據(jù)源也就是user_db2庫(kù)中添加
spring.shardingsphere.sharding.tables.user.database-strategy.inline.algorithm-expression=d$->{gender=='0'?1:2}
#開啟sql 輸出日志
spring.shardingsphere.props.sql.show=true
# 由于一個(gè)實(shí)體類對(duì)應(yīng)兩張表,所以會(huì)產(chǎn)生覆蓋操作,加上這個(gè)配置解決覆蓋問題
spring.main.allow-bean-definition-overriding=true
2.編寫測(cè)試代碼
@Test
void testAddUser() {
for (int i = 0;i < 10;i++){
User user = new User();
user.setPassword(UUID.randomUUID().toString().substring(0,5));
user.setUsername("-->" + i);
if (i % 2 == 0) user.setGender("0");
else user.setGender("1");
userMapper.insert(user);
}
}
3.數(shù)據(jù)庫(kù)查看

可以看到:gender為0,且id為偶數(shù)插入到了user_db1庫(kù)中的,user_1表。

可以看到:gender為0,且id為奇數(shù)插入到了user_db1庫(kù)中的,user_2表。

可以看到:gender為1,且id為偶數(shù)插入到了user_db2庫(kù)中的,user_1表。

可以看到:gender為1,且id為奇數(shù)插入到了user_db2庫(kù)中的,user_2表。
四、公共表的配置
有些表的數(shù)據(jù)量不大,需要在每個(gè)數(shù)據(jù)庫(kù)中都有,這時(shí)需要配置公共表。
向user_db1,和user_db2兩個(gè)數(shù)據(jù)庫(kù)都創(chuàng)建一個(gè)t_dict表
CREATE table t_dicit( id BIGINT(30) PRIMARY key, `dstatus` VARCHAR(255) not null, `description` VARCHAR(255) not null )
status和desc是mysql的兩個(gè)關(guān)鍵字,表的字段名盡量避開這些關(guān)鍵字,否則會(huì)發(fā)生運(yùn)行時(shí)異常。

1.配置application.properties
#指定當(dāng)前應(yīng)用的所有數(shù)據(jù)源標(biāo)識(shí)(由于后期可能會(huì)涉及到多個(gè)數(shù)據(jù)源,或讀寫分離等,這里要為每個(gè)數(shù)據(jù)源
# 起一個(gè)標(biāo)識(shí)名,然后為每個(gè)數(shù)據(jù)源具體配置)
spring.shardingsphere.datasource.names=d1,d2
#配置d1這個(gè)數(shù)據(jù)源,由于這里是水平分表,所以只需要一個(gè)數(shù)據(jù)源即可 其中d1代表該數(shù)據(jù)源的一個(gè)標(biāo)識(shí)
spring.shardingsphere.datasource.d1.type=com.alibaba.druid.pool.DruidDataSource
#指定鏈接驅(qū)動(dòng)
spring.shardingsphere.datasource.d1.driver-class-name=com.mysql.cj.jdbc.Driver
#指定鏈接url
spring.shardingsphere.datasource.d1.url=jdbc:mysql://localhost:3308/user_db1?useSSL=false&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC
#指定鏈接用戶名
spring.shardingsphere.datasource.d1.username=root
#指定鏈接密碼
spring.shardingsphere.datasource.d1.password=root
#由于是兩個(gè)數(shù)據(jù)庫(kù),所以要配置兩個(gè)數(shù)據(jù)源
#配置d2數(shù)據(jù)源
spring.shardingsphere.datasource.d2.type=com.alibaba.druid.pool.DruidDataSource
#指定鏈接驅(qū)動(dòng)
spring.shardingsphere.datasource.d2.driver-class-name=com.mysql.cj.jdbc.Driver
#指定鏈接url
spring.shardingsphere.datasource.d2.url=jdbc:mysql://localhost:3308/user_db2?useSSL=false&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC
#指定鏈接用戶名
spring.shardingsphere.datasource.d2.username=root
#指定鏈接密碼
spring.shardingsphere.datasource.d2.password=root
#指定數(shù)據(jù)庫(kù)和表的分布情況
#指定數(shù)據(jù)庫(kù)分布情況,數(shù)據(jù)庫(kù)里面表分布情況
#d$->{1..2}.user_$->{1..2} 表示在d1,d2數(shù)據(jù)源上都有user_1和user_2兩張表
spring.shardingsphere.sharding.tables.user.actual-data-nodes=d$->{1..2}.user_$->{1..2}
# 指定 user 表里面主鍵id 以及id的生成策略 SNOWFLAKE:表示用雪花算法生成該id
spring.shardingsphere.sharding.tables.user.key-generator.column=id
spring.shardingsphere.sharding.tables.user.key-generator.type=SNOWFLAKE
# 指定分片策略 約定 id 值偶數(shù)添加到 user_1 表,如果 id 是奇數(shù)添加到 user_2表
#指定要根據(jù)哪個(gè)字段進(jìn)行分表,這里根據(jù)id進(jìn)行分表
spring.shardingsphere.sharding.tables.user.table-strategy.inline.sharding-column=id
#執(zhí)行分表的規(guī)則:注意這里是$->{id% 2 + 1},由于偶數(shù)%2的結(jié)果為0,但是我們并沒有user_0這樣表
#所以我們要在取模的結(jié)果上+1 這樣就實(shí)現(xiàn)了如果是偶數(shù)那么取模的結(jié)果就是user_1,如果是奇數(shù)就是user_2
spring.shardingsphere.sharding.tables.user.table-strategy.inline.algorithm-expression=user_$->{id% 2 + 1}
#============================================================================================
#以上指定了分表策略,下面指定分庫(kù)策略,也就是gender為0則向user_db1中插入,為1則向user_db2中插入
spring.shardingsphere.sharding.tables.user.database-strategy.inline..sharding-column=gender
#如果gender為0 則表達(dá)式{gender=='0'?1:2}的結(jié)果就是1,則d$->{gender=='0'?1:2} = d1,就會(huì)向d1數(shù)據(jù)源也就是user_db1庫(kù)中添加
#如果gender為1 則表達(dá)式{gender=='0'?1:2}的結(jié)果就是2,則d$->{gender=='0'?1:2} = d2,就會(huì)向d1數(shù)據(jù)源也就是user_db2庫(kù)中添加
spring.shardingsphere.sharding.tables.user.database-strategy.inline.algorithm-expression=d$->{gender=='0'?1:2}
#============================================================================================
#配置公共表 在向t_dicit表插入數(shù)據(jù)時(shí) 這些默認(rèn)的數(shù)據(jù)源(d1,d2)的t_dicit表都會(huì)插入該數(shù)據(jù)
spring.shardingsphere.sharding.broadcast-tables=t_dicit
spring.shardingsphere.sharding.tables.t_dicit.key-generator.column=id
spring.shardingsphere.sharding.tables.t_dicit.key-generator.type=SNOWFLAKE
#開啟sql 輸出日志
spring.shardingsphere.props.sql.show=true
# 由于一個(gè)實(shí)體類對(duì)應(yīng)兩張表,所以會(huì)產(chǎn)生覆蓋操作,加上這個(gè)配置解決覆蓋問題
spring.main.allow-bean-definition-overriding=true
2.編寫實(shí)體類和mapper
@TableName("t_dicit")
@Data
public class Dict {
@TableId
private Long id;
private String dstatus;
private String description;
}
public interface DictMapper extends BaseMapper<Dict> {
}3.編寫測(cè)試程序
@Test
public void testDict(){
Dict dict = new Dict();
dict.setDescription("啟用狀態(tài)");
dict.setDstatus("A");
dictMapper.insert(dict);
}
4.查看日志發(fā)現(xiàn)分別向兩個(gè)數(shù)據(jù)源發(fā)送了sql

5.查看表


兩個(gè)庫(kù)的t_dicit表都有了該數(shù)據(jù)。
同樣如果是刪除公共表的數(shù)據(jù)也是同時(shí)將兩個(gè)數(shù)據(jù)庫(kù)中的記錄刪除。
@Test
public void testDictDel(){
dictMapper.deleteById(1270356973266165762L);
}
運(yùn)行日志:

兩個(gè)庫(kù)中的數(shù)據(jù)都被刪除。


總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
- SpringBoot+MybatisPlus實(shí)現(xiàn)sharding-jdbc分庫(kù)分表的示例代碼
- SpringBoot+MybatisPlus+Mysql+Sharding-JDBC分庫(kù)分表
- SpringBoot整合sharding-jdbc實(shí)現(xiàn)自定義分庫(kù)分表的實(shí)踐
- SpringBoot整合sharding-jdbc實(shí)現(xiàn)分庫(kù)分表與讀寫分離的示例
- SpringBoot 2.0 整合sharding-jdbc中間件實(shí)現(xiàn)數(shù)據(jù)分庫(kù)分表
- SpringBoot整合sharding-jdbc?實(shí)現(xiàn)分庫(kù)分表操作的示例代碼
相關(guān)文章
jdbc實(shí)現(xiàn)用戶注冊(cè)功能代碼示例
這篇文章主要介紹了jdbc實(shí)現(xiàn)用戶注冊(cè)功能,分享了相關(guān)代碼示例,小編覺得還是挺不錯(cuò)的,具有一定借鑒價(jià)值,需要的朋友可以參考下2018-01-01
使用arthas命令redefine實(shí)現(xiàn)Java熱更新(推薦)
今天分享一個(gè)非常重要的命令 redefine ,主要作用是加載外部的 .class 文件,用來替換 JVM 已經(jīng)加載的類,總結(jié)起來就是實(shí)現(xiàn)了 Java 的熱更新,感興趣的朋友跟隨小編一起看看吧2020-05-05
Mybatis如何傳入多個(gè)參數(shù)的實(shí)現(xiàn)代碼
這篇文章主要介紹了Mybatis如何傳入多個(gè)參數(shù)的實(shí)現(xiàn)代碼,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-12-12
JAVA基礎(chǔ)之控制臺(tái)輸入輸出的實(shí)例代碼
下面小編就為大家?guī)硪黄狫AVA基礎(chǔ)之控制臺(tái)輸入輸出的實(shí)例代碼。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2016-07-07
Java中計(jì)算集合中元素的出現(xiàn)次數(shù)統(tǒng)計(jì)
本文主要介紹了Java中計(jì)算集合中元素的出現(xiàn)次數(shù)統(tǒng)計(jì),使用Collections類配合HashMap來統(tǒng)計(jì)和java lamb 計(jì)算這兩種方式,具有一定的參考價(jià)值,感興趣可以了解一下2024-02-02
Java中數(shù)組array和列表list相互轉(zhuǎn)換
這篇文章主要介紹了Java中數(shù)組array和列表list相互轉(zhuǎn)換,在Java中,可以將數(shù)組(array)和列表(list)相互轉(zhuǎn)換,但需要注意一些細(xì)節(jié)和限制,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2023-09-09
Spring-boot oauth2使用RestTemplate進(jìn)行后臺(tái)自動(dòng)登錄的實(shí)現(xiàn)
這篇文章主要介紹了Spring-boot oauth2使用RestTemplate進(jìn)行后臺(tái)自動(dòng)登錄的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-07-07

