SpringBoot集成Sharding-JDBC實現(xiàn)分庫分表方式
一、環(huán)境搭建
1.創(chuàng)建一個springboot項目,引入以下依賴。
<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)建一個數(shù)據(jù)庫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表對應(yīng)的實體類和mapper
實體類代碼
@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)圖:

二、實現(xiàn)水平分表
需求:現(xiàn)在有兩個user表,一個是user_1,一個是user_2,當(dāng)id為偶數(shù)的時候向user_1表中插入數(shù)據(jù),當(dāng)id為奇數(shù)的時候向user_2表中插入數(shù)據(jù),實現(xiàn)水平分表。
1.配置application.properties
#指定當(dāng)前應(yīng)用的所有數(shù)據(jù)源標(biāo)識(由于后期可能會涉及到多個數(shù)據(jù)源,或讀寫分離等,這里要為每個數(shù)據(jù)源
# 起一個標(biāo)識名,然后為每個數(shù)據(jù)源具體配置)
spring.shardingsphere.datasource.names=d1
#配置d1這個數(shù)據(jù)源,由于這里是水平分表,所以只需要一個數(shù)據(jù)源即可 其中d1代表該數(shù)據(jù)源的一個標(biāo)識
spring.shardingsphere.datasource.d1.type=com.alibaba.druid.pool.DruidDataSource
#指定鏈接驅(qū)動
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
#由于是水平分表,所以會涉及到多張相同的表,這里指定這些表的分布情況:在哪個數(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ù)哪個字段進(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 這樣就實現(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
# 由于一個實體類對應(yīng)兩張表,所以會產(chǎn)生覆蓋操作,加上這個配置解決覆蓋問題
spring.main.allow-bean-definition-overriding=true
2.編寫測試代碼
@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ù)的時候,是向user_1表中插入的。

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

2.配置application.properties
#指定當(dāng)前應(yīng)用的所有數(shù)據(jù)源標(biāo)識(由于后期可能會涉及到多個數(shù)據(jù)源,或讀寫分離等,這里要為每個數(shù)據(jù)源
# 起一個標(biāo)識名,然后為每個數(shù)據(jù)源具體配置)
spring.shardingsphere.datasource.names=d1,d2
#配置d1這個數(shù)據(jù)源,由于這里是水平分表,所以只需要一個數(shù)據(jù)源即可 其中d1代表該數(shù)據(jù)源的一個標(biāo)識
spring.shardingsphere.datasource.d1.type=com.alibaba.druid.pool.DruidDataSource
#指定鏈接驅(qū)動
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
#由于是兩個數(shù)據(jù)庫,所以要配置兩個數(shù)據(jù)源
#配置d2數(shù)據(jù)源
spring.shardingsphere.datasource.d2.type=com.alibaba.druid.pool.DruidDataSource
#指定鏈接驅(qū)動
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ù)庫和表的分布情況
#指定數(shù)據(jù)庫分布情況,數(shù)據(jù)庫里面表分布情況
#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ù)哪個字段進(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 這樣就實現(xiàn)了如果是偶數(shù)那么取模的結(jié)果就是user_1,如果是奇數(shù)就是user_2
spring.shardingsphere.sharding.tables.user.table-strategy.inline.algorithm-expression=user_$->{id% 2 + 1}
#============================================================================================
#以上指定了分表策略,下面指定分庫策略,也就是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,就會向d1數(shù)據(jù)源也就是user_db1庫中添加
#如果gender為1 則表達(dá)式{gender=='0'?1:2}的結(jié)果就是2,則d$->{gender=='0'?1:2} = d2,就會向d1數(shù)據(jù)源也就是user_db2庫中添加
spring.shardingsphere.sharding.tables.user.database-strategy.inline.algorithm-expression=d$->{gender=='0'?1:2}
#開啟sql 輸出日志
spring.shardingsphere.props.sql.show=true
# 由于一個實體類對應(yīng)兩張表,所以會產(chǎn)生覆蓋操作,加上這個配置解決覆蓋問題
spring.main.allow-bean-definition-overriding=true
2.編寫測試代碼
@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ù)庫查看

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

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

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

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

1.配置application.properties
#指定當(dāng)前應(yīng)用的所有數(shù)據(jù)源標(biāo)識(由于后期可能會涉及到多個數(shù)據(jù)源,或讀寫分離等,這里要為每個數(shù)據(jù)源
# 起一個標(biāo)識名,然后為每個數(shù)據(jù)源具體配置)
spring.shardingsphere.datasource.names=d1,d2
#配置d1這個數(shù)據(jù)源,由于這里是水平分表,所以只需要一個數(shù)據(jù)源即可 其中d1代表該數(shù)據(jù)源的一個標(biāo)識
spring.shardingsphere.datasource.d1.type=com.alibaba.druid.pool.DruidDataSource
#指定鏈接驅(qū)動
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
#由于是兩個數(shù)據(jù)庫,所以要配置兩個數(shù)據(jù)源
#配置d2數(shù)據(jù)源
spring.shardingsphere.datasource.d2.type=com.alibaba.druid.pool.DruidDataSource
#指定鏈接驅(qū)動
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ù)庫和表的分布情況
#指定數(shù)據(jù)庫分布情況,數(shù)據(jù)庫里面表分布情況
#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ù)哪個字段進(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 這樣就實現(xiàn)了如果是偶數(shù)那么取模的結(jié)果就是user_1,如果是奇數(shù)就是user_2
spring.shardingsphere.sharding.tables.user.table-strategy.inline.algorithm-expression=user_$->{id% 2 + 1}
#============================================================================================
#以上指定了分表策略,下面指定分庫策略,也就是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,就會向d1數(shù)據(jù)源也就是user_db1庫中添加
#如果gender為1 則表達(dá)式{gender=='0'?1:2}的結(jié)果就是2,則d$->{gender=='0'?1:2} = d2,就會向d1數(shù)據(jù)源也就是user_db2庫中添加
spring.shardingsphere.sharding.tables.user.database-strategy.inline.algorithm-expression=d$->{gender=='0'?1:2}
#============================================================================================
#配置公共表 在向t_dicit表插入數(shù)據(jù)時 這些默認(rèn)的數(shù)據(jù)源(d1,d2)的t_dicit表都會插入該數(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
# 由于一個實體類對應(yīng)兩張表,所以會產(chǎn)生覆蓋操作,加上這個配置解決覆蓋問題
spring.main.allow-bean-definition-overriding=true
2.編寫實體類和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.編寫測試程序
@Test
public void testDict(){
Dict dict = new Dict();
dict.setDescription("啟用狀態(tài)");
dict.setDstatus("A");
dictMapper.insert(dict);
}
4.查看日志發(fā)現(xiàn)分別向兩個數(shù)據(jù)源發(fā)送了sql

5.查看表


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

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


總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
使用arthas命令redefine實現(xiàn)Java熱更新(推薦)
今天分享一個非常重要的命令 redefine ,主要作用是加載外部的 .class 文件,用來替換 JVM 已經(jīng)加載的類,總結(jié)起來就是實現(xiàn)了 Java 的熱更新,感興趣的朋友跟隨小編一起看看吧2020-05-05
Mybatis如何傳入多個參數(shù)的實現(xiàn)代碼
這篇文章主要介紹了Mybatis如何傳入多個參數(shù)的實現(xiàn)代碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-12-12
Java中計算集合中元素的出現(xiàn)次數(shù)統(tǒng)計
本文主要介紹了Java中計算集合中元素的出現(xiàn)次數(shù)統(tǒng)計,使用Collections類配合HashMap來統(tǒng)計和java lamb 計算這兩種方式,具有一定的參考價值,感興趣可以了解一下2024-02-02
Java中數(shù)組array和列表list相互轉(zhuǎn)換
這篇文章主要介紹了Java中數(shù)組array和列表list相互轉(zhuǎn)換,在Java中,可以將數(shù)組(array)和列表(list)相互轉(zhuǎn)換,但需要注意一些細(xì)節(jié)和限制,本文通過實例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2023-09-09
Spring-boot oauth2使用RestTemplate進(jìn)行后臺自動登錄的實現(xiàn)
這篇文章主要介紹了Spring-boot oauth2使用RestTemplate進(jìn)行后臺自動登錄的實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-07-07

