SpringBoot + MyBatis Plus + ShardingJDBC 集成教程
1. 技术栈概述
- SpringBoot:简化Spring应用开发的框架
- MyBatis Plus:MyBatis的增强工具,提供了CRUD操作、代码生成等便捷功能
- ShardingJDBC:Apache ShardingSphere的子项目,轻量级分布式数据库中间件,用于实现分库分表
2. 项目搭建
2.1 创建SpringBoot项目
可以通过Spring Initializr或IDE(如IntelliJ IDEA)创建SpringBoot项目。
2.2 添加依赖
在pom.xml中添加所需依赖:
<dependencies>
<!-- Spring Boot 核心依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- MyBatis Plus 依赖 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.3</version>
</dependency>
<!-- MyBatis Plus 代码生成器(可选) -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.4.1</version>
</dependency>
<!-- ShardingSphere-JDBC 依赖 -->
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId>
<version>5.2.1</version>
</dependency>
<!-- 数据库驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!-- 数据库连接池 -->
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>3.4.2</version>
</dependency>
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>1.33</version>
</dependency>
<!-- Lombok 简化代码 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
<optional>true</optional>
</dependency>
<!-- 代码生成器模板引擎(可选) -->
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
</dependency>
</dependencies>
3. 数据库准备
3.1 创建数据库和表
以用户表为例,我们将实现分库分表。创建两个数据库db0和db1,每个数据库中创建两张表user_0和user_1。
db0数据库中的表:
CREATE TABLE `user_0` (
`id` bigint NOT NULL,
`name` varchar(255) DEFAULT NULL,
`age` int DEFAULT NULL,
`email` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE `user_1` (
`id` bigint NOT NULL,
`name` varchar(255) DEFAULT NULL,
`age` int DEFAULT NULL,
`email` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
db1数据库中的表结构与db0相同。
4. 配置ShardingJDBC
4.1 配置application.yml
在application.yml中配置数据源和分片规则:
spring:
shardingsphere:
datasource:
names: ds0,ds1 # 数据源名称列表
ds0: # 第一个数据源
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
jdbc-url: jdbc:mysql://localhost:3306/db0?serverTimezone=UTC
username: root
password: root
ds1: # 第二个数据源
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
jdbc-url: jdbc:mysql://localhost:3306/db1?serverTimezone=UTC
username: root
password: root
rules:
sharding:
tables:
user: # 逻辑表名
actual-data-nodes: ds$->{0..1}.user_$->{0..1} # 实际数据节点
database-strategy: # 分库策略
standard:
sharding-column: id # 分片键
sharding-algorithm-name: database-inline # 分库算法
table-strategy: # 分表策略
standard:
sharding-column: id # 分片键
sharding-algorithm-name: table-inline # 分表算法
key-generate-strategy: # 主键生成策略
column: id # 主键列
key-generator-name: snowflake # 主键生成器
sharding-algorithms:
database-inline: # 分库算法定义
type: INLINE
props:
algorithm-expression: ds$->{id % 2} # 分片表达式
table-inline: # 分表算法定义
type: INLINE
props:
algorithm-expression: user_$->{id % 2} # 分片表达式
key-generators:
snowflake: # 主键生成器定义
type: SNOWFLAKE
props:
worker-id: 123
props:
sql-show: true # 显示SQL
mybatis-plus:
mapper-locations: classpath*:mapper/**/*.xml
type-aliases-package: com.example.entity
configuration:
map-underscore-to-camel-case: true # 开启下划线转驼峰
5. 代码实现
5.1 实体类
package com.example.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
@Data
@TableName("user") // 逻辑表名
public class User {
private Long id;
private String name;
private Integer age;
private String email;
}
5.2 Mapper接口
package com.example.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.entity.User;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface UserMapper extends BaseMapper<User> {
}
5.3 Service层
package com.example.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.example.entity.User;
public interface UserService extends IService<User> {
}
package com.example.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.entity.User;
import com.example.mapper.UserMapper;
import com.example.service.UserService;
import org.springframework.stereotype.Service;
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
}
5.4 Controller层
package com.example.controller;
import com.example.entity.User;
import com.example.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
// 添加用户
@PostMapping
public boolean save(@RequestBody User user) {
return userService.save(user);
}
// 根据ID查询用户
@GetMapping("/{id}")
public User getById(@PathVariable Long id) {
return userService.getById(id);
}
// 查询所有用户
@GetMapping
public List<User> list() {
return userService.list();
}
// 更新用户
@PutMapping
public boolean update(@RequestBody User user) {
return userService.updateById(user);
}
// 删除用户
@DeleteMapping("/{id}")
public boolean remove(@PathVariable Long id) {
return userService.removeById(id);
}
}
6. 启动类
package com.example;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@MapperScan("com.example.mapper") // 扫描Mapper接口
public class ShardingJdbcDemoApplication {
public static void main(String[] args) {
SpringApplication.run(ShardingJdbcDemoApplication.class, args);
}
}
7. 分片策略详解
7.1 行表达式分片策略(INLINE)
这是最简单的分片策略,使用Groovy表达式。在配置中我们使用了:
- 分库:
ds$->{id % 2}- 根据id对2取模,决定数据存储在哪个数据库 - 分表:
user_$->{id % 2}- 根据id对2取模,决定数据存储在哪个表
7.2 其他分片策略
7.2.1 标准分片策略(Standard)
适合需要根据单一字段进行精准查询和范围查询的场景。
7.2.2 复合分片策略(Complex)
适合根据多个字段进行分片的场景。
7.2.3 Hint分片策略
不依赖SQL条件,通过编程方式指定分片键。
8. 自定义分片算法
如果内置算法不满足需求,可以实现自定义分片算法:
package com.example.config;
import org.apache.shardingsphere.sharding.api.sharding.standard.PreciseShardingValue;
import org.apache.shardingsphere.sharding.api.sharding.standard.RangeShardingValue;
import org.apache.shardingsphere.sharding.api.sharding.standard.StandardShardingAlgorithm;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.Set;
public class CustomShardingAlgorithm implements StandardShardingAlgorithm<Long> {
@Override
public String doSharding(Collection<String> availableTargetNames, PreciseShardingValue<Long> shardingValue) {
Long value = shardingValue.getValue();
for (String targetName : availableTargetNames) {
if (targetName.endsWith(String.valueOf(value % 2))) {
return targetName;
}
}
throw new UnsupportedOperationException();
}
@Override
public Collection<String> doSharding(Collection<String> availableTargetNames, RangeShardingValue<Long> shardingValue) {
Set<String> result = new LinkedHashSet<>();
// 实现范围查询的分片逻辑
return result;
}
@Override
public void init() {
// 初始化逻辑
}
@Override
public String getType() {
return "CUSTOM"; // 算法类型名称
}
}
在配置文件中引用自定义算法:
spring:
shardingsphere:
rules:
sharding:
sharding-algorithms:
custom-algorithm:
type: CLASS_BASED
props:
strategy: STANDARD
algorithmClassName: com.example.config.CustomShardingAlgorithm
9. 测试
9.1 测试数据插入
使用Postman或其他工具发送POST请求:
POST http://localhost:8080/user
Content-Type: application/json
{
"name": "张三",
"age": 25,
"email": "zhangsan@example.com"
}
9.2 测试数据查询
查询所有用户:
GET http://localhost:8080/user
根据ID查询用户:
GET http://localhost:8080/user/{id}
10. 常见问题与解决方案
10.1 数据不一致
问题:分片键选择不当导致数据分布不均匀
解决方案:选择离散度高的字段作为分片键,如用户ID、订单ID等
10.2 跨库查询性能问题
问题:未使用分片键的查询会导致全库扫描
解决方案:
- 尽量在查询中包含分片键
- 合理设计表结构,减少跨库Join操作
- 考虑使用绑定表
10.3 主键冲突
问题:不同分片可能产生重复的主键
解决方案:使用分布式ID生成器,如雪花算法(Snowflake)
11. 最佳实践
- 分片键选择:选择查询频繁、离散度高的字段
- 避免热点数据:确保数据均匀分布在各个分片
- 合理设置分片数量:避免过多分片导致的资源浪费
- 使用绑定表:相关联的表使用相同的分片键和分片策略
- 注意事务一致性:跨库事务需要特别处理
- 监控与调优:实时监控分片执行情况,及时优化
12. 总结
通过本文的教程,我们学习了如何在SpringBoot项目中集成MyBatis Plus和ShardingJDBC实现分库分表。ShardingJDBC作为一款轻量级的中间件,以jar包形式提供服务,无需额外部署,非常适合中小型项目使用。结合MyBatis Plus的便捷功能,可以大幅提高开发效率。
在实际项目中,需要根据业务需求选择合适的分片策略,并注意处理可能出现的问题,如数据一致性、跨库查询性能等。