1 概述
本文主要講述了如何使用
ShardingSphere
(其中的
Sharding-JDBC
)和
MyBatisPlus
進行分庫分表,具體步驟包括:
- 準備資料庫環境
- 準備依賴
- 編寫配置檔案
- 測試
2 準備資料庫環境
2.1 兩庫六表
準備好兩個庫:
-
test0
-
test1
在兩個庫中分别建立三個字段一樣的表:
-
user0
-
user1
-
user2
字段如下:
這樣就準備了兩個庫以及其中的六個表了。
2.2 (可選) MyBatis Plus Generator
代碼生成表
MyBatis Plus Generator
因為
MyBatis Plus Generator
生成的
Controller
等代碼預設是按照表名命名的,這樣就會生成類似
User0
、
User0Controller
這樣的命名,是以這裡建立一個叫
user
的表,僅僅用于代碼的生成,裡面不會存放任何的資料:
3 建立項目
建立
Spring Boot
項目并引入如下依賴:
-
Druid
-
MyBatis Plus starter
-
MyBaits Plus Generator
-
Velocity core
-
ShardingSphere
-
(一個雪花Yitter
生成器)id
Maven
如下:
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.3.1</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.5.0</version>
</dependency>
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>2.3</version>
</dependency>
<dependency>
<groupId>org.realityforge.org.jetbrains.annotations</groupId>
<artifactId>org.jetbrains.annotations</artifactId>
<version>1.7.0</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.6</version>
</dependency>
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-jdbc-spring-boot-starter</artifactId>
<version>4.1.1</version>
</dependency>
<dependency>
<groupId>com.github.yitter</groupId>
<artifactId>yitter-idgenerator</artifactId>
<version>1.0.6</version>
</dependency>
Gradle
如下:
implementation 'com.baomidou:mybatis-plus-boot-starter:3.4.3.1'
implementation 'org.apache.velocity:velocity-engine-core:2.3'
implementation 'org.realityforge.org.jetbrains.annotations:org.jetbrains.annotations:1.7.0'
implementation 'com.alibaba:druid:1.2.6'
implementation 'org.apache.shardingsphere:sharding-jdbc-spring-boot-starter:4.1.1'
implementation 'com.github.yitter:yitter-idgenerator:1.0.6'
4 配置檔案
配置檔案可以參考ShardingSphere文檔,這裡給出一個示例配置:
spring:
shardingsphere:
datasource:
names: test0,test1 # 資料源,這裡為了友善直接使用庫名的名稱
test0:
type: com.alibaba.druid.pool.DruidDataSource # Druid連接配接池
url: jdbc:mysql://127.0.0.1:3306/test0 # 連接配接test0的url
username: root
password: 123456
test1:
type: com.alibaba.druid.pool.DruidDataSource # Druid連接配接池
url: jdbc:mysql://127.0.0.1:3306/test1 # 連接配接test1的url
username: root
password: 123456
sharding:
default-database-strategy: # 預設分庫政策
inline:
sharding-column: age # 表示根據age列進行分庫
algorithm-expression: test$->{age % 2} # 根據age對2的模進行分庫,模為0表示test0庫,模為1表示test1庫
tables:
user:
actual-data-nodes: test$->{0..1}.user$->{0..2} # 表的名字,test$->{0..1}可以表示test0、test1兩個庫
# user$->{0..2}表示user0、user1、user2三個庫
table-strategy: # 分表政策
inline:
sharding-column: id # 根據哪一列進行分表,id表示根據列名為"id"的列分表
algorithm-expression: user$->{id%3} # 分表規則為id對3取模,id%3為0表示分到user0表
# id%3為1表示分到user1表,id%3為2表示分到user2表
props:
sql:
show:
true # 列印sql
這裡使用自動取模分片政策,
ShardingShphere
内置了如下分片算法:
- 自動分片算法:取模分片、哈希取模分片、基于分片容量的範圍分片、基于分片邊界的範圍分片、自動時間段分片
- 标準分片算法:行表達式分片、時間範圍分片
- 複合行表達式分片
-
行表達式分片Hint
如果不能滿足需要還可以自定義分片算法,具體請看官方文檔。
5 測試代碼生成
使用
MyBaits Plus Generator
生成相應代碼,具體使用可以參考筆者之前的文章,這裡直接放上生成類的代碼:
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.config.*;
public class MyBatisPlusGenerator {
public static void main(String[] args) {
DataSourceConfig dataSourceConfig = new DataSourceConfig.Builder("jdbc:mysql://localhost:3306/test0", "root", "123456").build();
String projectPath = System.getProperty("user.dir");
StrategyConfig strategyConfig = new StrategyConfig.Builder().addInclude("user").build();
GlobalConfig globalConfig = new GlobalConfig.Builder().outputDir(projectPath + "/src/main/java").openDir(false).build();
PackageConfig packageConfig = new PackageConfig.Builder().moduleName("user").parent("com.example.demo").serviceImpl("service").build();
new AutoGenerator(dataSourceConfig).global(globalConfig).packageInfo(packageConfig).strategy(strategyConfig).execute();
}
}
把
UserController
類修改如下:
@RestController
@RequestMapping("/user")
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class UserController {
private final Random random = new Random();
private final UserServiceImpl service;
@GetMapping("/select")
public List<User> select(){
return service.list();
}
@GetMapping("/insert")
public boolean insert(){
return service.save(User.builder().age(random.nextInt(80)+20).name("test name").email("[email protected]").build());
}
}
6 增加雪花 id
生成器
id
首先修改
User
類,增加一個
@Builder
注解,同時修改
id
的生成政策,使用
IdType.ASSIGN_ID
:
@Builder
public class User implements Serializable {
@TableId(type = IdType.ASSIGN_ID)
private Long id;
//...
}
建立
id
生成器類:
import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator;
import com.github.yitter.contract.IdGeneratorOptions;
import com.github.yitter.idgen.YitIdHelper;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
@Component
public class IdGenerator implements IdentifierGenerator {
final IdGeneratorOptions options = new IdGeneratorOptions((short) 1);
@PostConstruct
public void init() {
YitIdHelper.setIdGenerator(options);
}
@Override
public Long nextId(Object entity) {
return YitIdHelper.nextId();
}
}
這樣生成
id
的時候,就會自動調用
nextId()
方法,其中的
id
生成器可以根據需要進行替換,換成其他雪花
id
生成器或分布式
id
生成器。
配置的時候可以參考MyBaits Plus 自定義ID生成器文檔。
7 測試
先随機插入三條資料,重新整理三次如下頁面:
localhost:8080/test/user/insert
可以看到執行了三次插入操作,插入的三個表分别是:
-
test0.user2
-
test0.user0
-
test0.user2
因為這裡測試的時候年齡都恰好是偶數,都插入到了
test0
表。
檢視資料:
http://localhost:8080/user/select
日志輸出如下:
表示這是對六個表查詢的結果,并将最後的結果進行聚合傳回。
8 參考源碼
Java
版:
- Github
- 碼雲
- CODE.CHINA
Kotlin
版:
- Github
- 碼雲
- CODE.CHINA