1 概述
之前筆者寫過兩篇文章:
這里將兩者結合起來,實現讀寫分離+分庫分表的功能。關於環境的配置本文將進行簡化敘述,詳細可以參考前兩篇文章。
2 環境
MySQL 8.0.25
(Docker
)MyBatis Plus 3.4.3.1
MyBatis Plus Generator 3.5.0
Druid 1.2.6
ShardingSphere 4.1.1
Yitter 1.0.6
(一個雪花id
生成器)
3 數據庫環境准備
由於環境准備不是本文的重點,一主一從的主從復制環境可以參考此處搭建。
准備好環境,本地啟動兩個MySQL
,主節點環境:
- 名字:
master
- 端口:
3306
- 數據庫:兩個庫(
test0
、test1
) - 數據表:六個表,每個庫三個(
test0.user0
、test0.user1
、test0.user2
、test1.user0
、test1.user1
、test1.user2
)
從節點環境:
- 名字:
slave
- 端口:
3307
- 數據庫:兩個庫(
test0
、test1
) - 數據表:六個表,每個庫三個(
test0.user0
、test0.user1
、test0.user2
、test1.user0
、test1.user1
、test1.user2
)
主庫配置文件:
[mysqld]
server-id=1
binlog-do-db=test0
binlog-do-db=test1
從庫配置文件:
[mysqld]
server-id=2
replicate-do-db=test0
replicate-do-db=test1
完整的數據庫腳本和MySQL
配置文件放在文末的源碼鏈接中。
4 新建項目
新建項目並引入如下依賴:
Druid
MyBatis Plus starter
MyBaits Plus Generator
Velocity core
ShardingSphere
Yitter
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'
5 配置文件
spring:
shardingsphere:
datasource:
names: master-test0,master-test1,slave-test0,slave-test1 # 數據源節點名字
# master-test0表示主節點的test0庫,master-test1表示主節點的test1庫
# slave-test0表示從節點的test0庫,slave-test1表示從節點的test1庫
master-test0:
type: com.alibaba.druid.pool.DruidDataSource # 連接池
url: jdbc:mysql://127.0.0.1:3306/test0 # 主節點的test0庫
username: root
password: 123456
master-test1:
type: com.alibaba.druid.pool.DruidDataSource
url: jdbc:mysql://127.0.0.1:3306/test1 # 主節點的test1庫
username: root
password: 123456
slave-test0:
type: com.alibaba.druid.pool.DruidDataSource
url: jdbc:mysql://127.0.0.1:3307/test0 # 從節點的test0庫,端口3307
username: root
password: 123456
slave-test1:
type: com.alibaba.druid.pool.DruidDataSource
url: jdbc:mysql://127.0.0.1:3307/test1 # 從節點的test1庫,端口3307
username: root
password: 123456
sharding:
default-database-strategy:
inline:
sharding-column: age # 按照哪一列分庫
algorithm-expression: master-test$->{age % 2} # 分庫規則為對年齡取模
tables:
user:
actual-data-nodes: master-test$->{0..1}.user$->{0..2} # 分表的節點,格式為 [數據源.表名]
table-strategy:
inline:
sharding-column: id # 按照哪一列分表
algorithm-expression: user$->{id%3} # 分表規則,對id取模
master-slave-rules: # 讀寫分離的規則
master-test0: # 哪一個主節點
master-datasource-name: master-test0 # 指定主節點名字
slave-data-source-names: slave-test0 # 指定從節點名字
master-test1:
master-datasource-name: master-test1
slave-data-source-names: slave-test1
props:
sql:
show:
true # 打印SQL
6 准備測試代碼
使用MyBatis 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();
}
}
實體類加上@Builder
,同時設置id
類型為IdType.ASSIGN_ID
:
@Builder
public class User implements Serializable {
@TableId(type = IdType.ASSIGN_ID)
private Long id;
//...
}
修改Controller
類:
@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("test@test.com").build());
}
}
同時新增一個雪花id
生成器類(具體配置方法可以參考MyBatis Plus
官方文檔):
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();
}
}
7 測試
刷新幾次插入頁面:
http://localhost:8080/user/insert
從輸出可以看到插入都是在主節點中進行的:
而查詢的時候:
http://localhost:8080/user/select
輸出如下:
是在從節點查詢的。
8 參考代碼
Java
版:
Kotlin
版: