在分布式系统开发中,随着业务规模的扩大,单库单表的架构往往会面临性能瓶颈------数据量激增导致查询缓慢、写入耗时变长,甚至出现表锁阻塞等问题。MyBatis-Plus(简称MP)作为MyBatis的增强工具,不仅简化了CRUD操作,还能与分库分表中间件无缝集成,轻松解决数据量大的存储难题。本文将从分库分表的核心概念入手,结合Spring Boot实战,通过详细的示例代码讲解MyBatis-Plus实现分库分表的完整流程,并补充相关拓展知识点,帮助开发者快速上手。
一、分库分表核心概念:为什么需要它?
在讲解实操前,我们先明确分库分表的核心逻辑------本质是"拆分"与"路由":通过将海量数据拆分到多个数据库或数据表中,降低单库单表的数据量,从而提升读写性能;同时通过中间件实现数据的自动路由,让开发者像操作单库单表一样操作拆分后的数据源。
1.1 分库 vs 分表
-
分表:将一张大表拆分为多张结构相同的小表,所有表仍存储在同一个数据库中。核心解决"单表数据量过大"的问题,比如将一张1000万行的用户表拆分为10张100万行的小表。
-
分库:将一个数据库拆分为多个数据库,每个数据库存储部分数据。核心解决"单库压力过大"的问题,比如将用户数据按地域拆分为北京库、上海库、广州库,分别存储对应区域的用户信息。
1.2 拆分方式:水平 vs 垂直
水平拆分(横向拆分)
按"数据行"拆分,拆分后每张表/每个库的结构完全相同,数据按规则分布。比如:
-
用户表按user_id取模拆分:user_id%2=0存user_0表,user_id%2=1存user_1表
-
订单表按创建时间拆分:2024年1月数据存order_202401表,2月数据存order_202402表
适用场景:数据量巨大,且查询多基于拆分字段(如user_id、时间)。
垂直拆分(纵向拆分)
按"数据列"拆分,拆分后每张表/每个库的结构不同,存储不同维度的字段。比如:
-
用户表拆分为user_base(存储id、姓名、手机号等核心字段)和user_extend(存储头像、简介、地址等扩展字段)
-
数据库按业务拆分:用户库(存储用户信息)、订单库(存储订单信息)、商品库(存储商品信息)
适用场景:表字段过多,或不同字段的查询频率差异大(如核心字段高频查询,扩展字段低频查询)。
核心原则:拆分后尽量避免跨库跨表查询(如联合查询多个拆分表),否则会降低性能。若必须跨查询,需通过中间件或业务逻辑优化。
二、实战准备:技术栈与环境搭建
本文采用"Spring Boot + MyBatis-Plus + Sharding-JDBC"实现分库分表------Sharding-JDBC是阿里开源的轻量级分库分表中间件,无需额外部署独立服务,可直接集成到应用中,支持所有基于JDBC的ORM框架(包括MyBatis-Plus)。
2.1 技术栈版本
| 技术 | 版本 | 说明 |
|---|---|---|
| Spring Boot | 2.7.10 | 稳定版,适配大多数中间件 |
| MyBatis-Plus | 3.5.3.1 | 支持Sharding-JDBC的增强功能 |
| Sharding-JDBC | 4.1.1 | 轻量级分库分表中间件 |
| MySQL | 8.0.x | 关系型数据库(示例用) |
| Lombok | 1.18.24 | 简化实体类代码(可选) |
2.2 依赖引入(pom.xml)
在Spring Boot项目中引入核心依赖,重点是MyBatis-Plus Starter和Sharding-JDBC Starter:
xml
<!-- Spring Boot 核心依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- MyBatis-Plus Starter -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.3.1</version>
</dependency>
<!-- Sharding-JDBC Starter(分库分表核心) -->
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-jdbc-spring-boot-starter</artifactId>
<version>4.1.1</version>
</dependency>
<!-- MySQL 驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!-- Lombok(简化代码) -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- 测试依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
2.3 数据库准备
本文将演示3个核心场景:水平分表、垂直分表、水平分库。提前创建对应的数据库和表:
-
水平分表场景:1个数据库(sharding_db),2张用户表(t_user_0、t_user_1),结构完全相同。
-
垂直分表场景:1个数据库(sharding_db),2张用户相关表(t_user_base、t_user_extend),结构不同。
-
水平分库场景:2个数据库(sharding_db_0、sharding_db_1),每个库各1张订单表(t_order),结构完全相同。
创建SQL示例(以MySQL为例):
sql
-- 1. 水平分表:创建数据库sharding_db
CREATE DATABASE IF NOT EXISTS sharding_db CHARACTER SET utf8mb4;
USE sharding_db;
-- 水平分表:t_user_0 和 t_user_1(结构相同)
CREATE TABLE IF NOT EXISTS t_user_0 (
id BIGINT NOT NULL COMMENT '用户ID',
username VARCHAR(50) NOT NULL COMMENT '用户名',
age INT NOT NULL COMMENT '年龄',
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS t_user_1 LIKE t_user_0;
-- 垂直分表:t_user_base(核心字段)和 t_user_extend(扩展字段)
CREATE TABLE IF NOT EXISTS t_user_base (
id BIGINT NOT NULL COMMENT '用户ID',
username VARCHAR(50) NOT NULL COMMENT '用户名',
phone VARCHAR(20) NOT NULL COMMENT '手机号',
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS t_user_extend (
id BIGINT NOT NULL COMMENT '用户ID(与t_user_base关联)',
avatar VARCHAR(255) COMMENT '头像地址',
address VARCHAR(255) COMMENT '详细地址',
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- 2. 水平分库:创建2个数据库sharding_db_0、sharding_db_1
CREATE DATABASE IF NOT EXISTS sharding_db_0 CHARACTER SET utf8mb4;
CREATE DATABASE IF NOT EXISTS sharding_db_1 CHARACTER SET utf8mb4;
-- 每个库创建t_order表(结构相同)
USE sharding_db_0;
CREATE TABLE IF NOT EXISTS t_order (
id BIGINT NOT NULL COMMENT '订单ID',
user_id BIGINT NOT NULL COMMENT '用户ID',
order_no VARCHAR(50) NOT NULL COMMENT '订单编号',
amount DECIMAL(10,2) NOT NULL COMMENT '订单金额',
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
USE sharding_db_1;
CREATE TABLE IF NOT EXISTS t_order LIKE sharding_db_0.t_order;
三、核心实战:MyBatis-Plus 分库分表示例
Sharding-JDBC的核心配置是"数据源配置"和"分片规则配置"------通过配置告诉中间件:数据拆分到哪些库/表?按什么规则路由?下面结合3个场景逐一演示。
场景1:水平分表(按用户ID取模拆分)
需求:将用户数据按user_id取模拆分到t_user_0和t_user_1表(user_id%2=0→t_user_0,user_id%2=1→t_user_1),使用MyBatis-Plus实现CRUD操作。
3.1.1 配置文件(application.yml)
yaml
spring:
# Sharding-JDBC 配置
shardingsphere:
# 数据源配置(水平分表仅1个数据源)
datasources:
# 数据源名称(自定义)
ds0:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/sharding_db?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
username: root
password: root123456
# 分片规则配置
sharding:
# 表分片规则(重点)
tables:
# 逻辑表名(自定义,对应MP实体类的表名)
t_user:
# 数据节点:格式为 数据源名称.真实表名,多个表用逗号分隔
actual-data-nodes: ds0.t_user_$->{0..1}
# 表分片策略(按user_id取模)
table-strategy:
inline:
# 分片键(即按哪个字段拆分)
sharding-column: id
# 分片表达式(user_id%2得到0或1,对应t_user_0和t_user_1)
algorithm-expression: t_user_$->{id % 2}
# 主键生成策略(可选,MP也可配置)
key-generators:
t_user_key:
type: SNOWFLAKE
props:
worker-id: 123
# 打印SQL(开发环境开启,便于调试)
props:
sql:
show: true
# MyBatis-Plus 配置
mybatis-plus:
mapper-locations: classpath:mapper/*.xml
type-aliases-package: com.example.sharding.entity
configuration:
map-underscore-to-camel-case: true # 下划线转驼峰
global-config:
db-config:
id-type: ASSIGN_ID # 主键生成策略(雪花算法,与Sharding-JDBC一致)
3.1.2 实体类(User.java)
java
package com.example.sharding.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.time.LocalDateTime;
@Data
@TableName("t_user") // 对应Sharding-JDBC配置的逻辑表名
public class User {
private Long id; // 分片键(用户ID)
private String username;
private Integer age;
private LocalDateTime createTime; // 对应数据库的create_time(下划线转驼峰)
}
3.1.3 Mapper接口(UserMapper.java)
MyBatis-Plus的BaseMapper已提供CRUD方法,直接继承即可:
java
package com.example.sharding.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.sharding.entity.User;
import org.springframework.stereotype.Repository;
@Repository
public interface UserMapper extends BaseMapper<User> {
}
3.1.4 测试类(UserMapperTest.java)
通过测试验证数据是否按规则路由到对应表:
java
package com.example.sharding.mapper;
import com.example.sharding.entity.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.time.LocalDateTime;
import java.util.List;
@SpringBootTest
public class UserMapperTest {
@Autowired
private UserMapper userMapper;
// 测试新增:验证按id取模拆分
@Test
public void testInsert() {
// id=1(1%2=1→t_user_1)
User user1 = new User();
user1.setId(1L);
user1.setUsername("张三");
user1.setAge(25);
user1.setCreateTime(LocalDateTime.now());
userMapper.insert(user1);
// id=2(2%2=0→t_user_0)
User user2 = new User();
user2.setId(2L);
user2.setUsername("李四");
user2.setAge(30);
user2.setCreateTime(LocalDateTime.now());
userMapper.insert(user2);
System.out.println("新增成功,可去数据库查看t_user_0和t_user_1表数据");
}
// 测试查询:验证自动路由到对应表
@Test
public void testSelect() {
// 查询id=1的用户(应从t_user_1查询)
User user1 = userMapper.selectById(1L);
System.out.println("id=1的用户:" + user1);
// 查询所有用户(自动聚合t_user_0和t_user_1的数据)
List<User> userList = userMapper.selectList(null);
System.out.println("所有用户:" + userList);
}
}
3.1.5 测试结果说明
-
执行testInsert后,id=1的用户会插入到t_user_1表,id=2的用户会插入到t_user_0表。
-
执行testSelect时,selectById(1L)会自动路由到t_user_1表查询;selectList(null)会自动查询t_user_0和t_user_1表,将结果聚合后返回。
场景2:垂直分表(按字段维度拆分)
需求:将用户数据拆分为核心字段(t_user_base)和扩展字段(t_user_extend),通过MyBatis-Plus实现关联查询和分别插入。
3.2.1 配置文件(application.yml)
垂直分表无需复杂的分片规则,只需配置数据源,MP通过不同的实体类和Mapper对应不同的表:
yaml
spring:
shardingsphere:
datasources:
ds0:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/sharding_db?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
username: root
password: root123456
# 垂直分表无需表分片规则(直接操作真实表)
props:
sql:
show: true
# MyBatis-Plus 配置(不变)
mybatis-plus:
mapper-locations: classpath:mapper/*.xml
type-aliases-package: com.example.sharding.entity
configuration:
map-underscore-to-camel-case: true
global-config:
db-config:
id-type: ASSIGN_ID
3.2.2 实体类(UserBase.java + UserExtend.java)
java
// UserBase.java(对应t_user_base表,核心字段)
package com.example.sharding.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.time.LocalDateTime;
@Data
@TableName("t_user_base") // 对应真实表名
public class UserBase {
private Long id; // 关联键
private String username;
private String phone;
private LocalDateTime createTime;
}
// UserExtend.java(对应t_user_extend表,扩展字段)
package com.example.sharding.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.time.LocalDateTime;
@Data
@TableName("t_user_extend") // 对应真实表名
public class UserExtend {
private Long id; // 与UserBase的id关联
private String avatar;
private String address;
private LocalDateTime updateTime;
}
3.2.3 Mapper接口(UserBaseMapper.java + UserExtendMapper.java)
java
package com.example.sharding.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.sharding.entity.UserBase;
import org.springframework.stereotype.Repository;
@Repository
public interface UserBaseMapper extends BaseMapper<UserBase> {
}
package com.example.sharding.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.sharding.entity.UserExtend;
import org.springframework.stereotype.Repository;
@Repository
public interface UserExtendMapper extends BaseMapper<UserExtend> {
}
3.2.4 关联查询(自定义XML)
垂直分表的关联查询需通过XML自定义SQL(关联t_user_base和t_user_extend),创建UserMapper.xml:
xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.sharding.mapper.UserBaseMapper">
<!-- 关联查询用户完整信息(核心字段+扩展字段) -->
<select id="selectUserFullInfo" resultType="java.util.Map">
SELECT
ub.id, ub.username, ub.phone, ub.create_time,
ue.avatar, ue.address, ue.update_time
FROM t_user_base ub
LEFT JOIN t_user_extend ue ON ub.id = ue.id
WHERE ub.id = #{id}
</select>
</mapper>
在UserBaseMapper中添加方法:
java
Map<String, Object> selectUserFullInfo(Long id);
3.2.5 测试类
java
package com.example.sharding.mapper;
import com.example.sharding.entity.UserBase;
import com.example.sharding.entity.UserExtend;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.time.LocalDateTime;
import java.util.Map;
@SpringBootTest
public class UserVerticalShardingTest {
@Autowired
private UserBaseMapper userBaseMapper;
@Autowired
private UserExtendMapper userExtendMapper;
// 测试分别插入核心字段和扩展字段
@Test
public void testInsertVertical() {
// 插入核心字段(t_user_base)
UserBase userBase = new UserBase();
userBase.setId(3L);
userBase.setUsername("王五");
userBase.setPhone("13800138000");
userBase.setCreateTime(LocalDateTime.now());
userBaseMapper.insert(userBase);
// 插入扩展字段(t_user_extend)
UserExtend userExtend = new UserExtend();
userExtend.setId(3L); // 与userBase的id关联
userExtend.setAvatar("https://xxx.com/avatar/3.jpg");
userExtend.setAddress("北京市海淀区");
userExtendMapper.insert(userExtend);
System.out.println("垂直分表插入成功");
}
// 测试关联查询完整信息
@Test
public void testSelectFullInfo() {
Map<String, Object> userInfo = userBaseMapper.selectUserFullInfo(3L);
System.out.println("用户完整信息:" + userInfo);
}
}
场景3:水平分库(按用户ID取模拆分数据库)
需求:将订单数据按user_id取模拆分到sharding_db_0和sharding_db_1(user_id%2=0→sharding_db_0,user_id%2=1→sharding_db_1),每个库中的订单表为t_order。
3.3.1 配置文件(application.yml)
水平分库需配置多个数据源,并指定数据库分片规则和表分片规则(本例表不分片,仅库分片):
yaml
spring:
shardingsphere:
# 多数据源配置(sharding_db_0和sharding_db_1)
datasources:
ds0:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/sharding_db_0?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
username: root
password: root123456
ds1:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/sharding_db_1?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
username: root
password: root123456
# 分片规则配置(库分片+表分片)
sharding:
# 数据库分片规则(按user_id取模)
default-database-strategy:
inline:
sharding-column: user_id # 库分片键(用户ID)
algorithm-expression: ds$->{user_id % 2} # 分片表达式(user_id%2=0→ds0,1→ds1)
# 表分片规则(本例表不分片,仅指定真实表名)
tables:
t_order:
actual-data-nodes: ds$->{0..1}.t_order # 数据节点:ds0.t_order 和 ds1.t_order
# 主键生成策略
key-generators:
t_order_key:
type: SNOWFLAKE
props:
worker-id: 123
props:
sql:
show: true
# MyBatis-Plus 配置(不变)
mybatis-plus:
mapper-locations: classpath:mapper/*.xml
type-aliases-package: com.example.sharding.entity
configuration:
map-underscore-to-camel-case: true
global-config:
db-config:
id-type: ASSIGN_ID
3.3.2 实体类(Order.java)
java
package com.example.sharding.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDateTime;
@Data
@TableName("t_order") // 对应真实表名(每个库都有t_order表)
public class Order {
private Long id; // 订单ID
private Long userId; // 库分片键(用户ID)
private String orderNo;
private BigDecimal amount;
private LocalDateTime createTime;
}
3.3.3 Mapper接口(OrderMapper.java)
java
package com.example.sharding.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.sharding.entity.Order;
import org.springframework.stereotype.Repository;
@Repository
public interface OrderMapper extends BaseMapper<Order> {
}
3.3.4 测试类
java
package com.example.sharding.mapper;
import com.example.sharding.entity.Order;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
@SpringBootTest
public class OrderMapperTest {
@Autowired
private OrderMapper orderMapper;
// 测试新增订单:验证按userId分库
@Test
public void testInsertOrder() {
// userId=1(1%2=1→ds1→sharding_db_1库)
Order order1 = new Order();
order1.setId(1001L);
order1.setUserId(1L);
order1.setOrderNo("ORDER20240501001");
order1.setAmount(new BigDecimal("99.99"));
order1.setCreateTime(LocalDateTime.now());
orderMapper.insert(order1);
// userId=2(2%2=0→ds0→sharding_db_0库)
Order order2 = new Order();
order2.setId(1002L);
order2.setUserId(2L);
order2.setOrderNo("ORDER20240501002");
order2.setAmount(new BigDecimal("199.99"));
order2.setCreateTime(LocalDateTime.now());
orderMapper.insert(order2);
System.out.println("水平分库新增订单成功,可去sharding_db_0和sharding_db_1库查看t_order表");
}
// 测试查询订单:验证自动路由到对应库
@Test
public void testSelectOrder() {
// 查询userId=1的订单(应从sharding_db_1库查询)
List<Order> orderList1 = orderMapper.selectList(
Wrappers.<Order>lambdaQuery().eq(Order::getUserId, 1L)
);
System.out.println("userId=1的订单:" + orderList1);
// 查询userId=2的订单(应从sharding_db_0库查询)
List<Order> orderList2 = orderMapper.selectList(
Wrappers.<Order>lambdaQuery().eq(Order::getUserId, 2L)
);
System.out.println("userId=2的订单:" + orderList2);
}
}
四、拓展知识点:分库分表进阶技巧
4.1 分片键选择技巧
-
优先选择高频查询字段:比如订单表常用userId查询,用userId作为分片键,避免跨库查询。
-
避免热点数据集中:比如按时间分片时,若某时间段数据量激增(如电商大促),会导致单库/单表压力过大,可结合其他字段(如userId)复合分片。
-
尽量使用整数类型:整数类型的分片键(如id、userId)取模效率高于字符串类型(如订单号)。
4.2 分库分表后的事务处理
分库分表后,单库事务仍可用Spring的@Transactional,但跨库事务会失效。解决方案:
-
柔性事务:使用Seata、Hmily等分布式事务框架,支持TCC、SAGA等模式。
-
业务优化:尽量避免跨库事务,通过"最终一致性"替代强一致性(如用消息队列异步补偿)。
4.3 MyBatis-Plus 高级特性适配
-
分页插件:分库分表场景下,MP的分页插件需结合Sharding-JDBC使用,配置方式不变,Sharding-JDBC会自动处理跨表分页。
-
条件构造器:支持所有MP的条件构造器(如lambdaQuery、eq、like等),Sharding-JDBC会自动将条件转换为跨库/跨表查询。
-
逻辑删除:配置方式与单库单表一致,需确保所有拆分表都添加逻辑删除字段(如is_deleted)。
4.4 分库分表中间件对比
| 中间件 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| Sharding-JDBC | 轻量级、无独立部署、适配所有JDBC框架、性能好 | 不支持读写分离自动切换(需额外配置)、动态扩容复杂 | 中小型分布式系统、对性能要求高的场景 |
| MyCat | 支持读写分离、动态扩容、功能强大 | 需独立部署、性能略低于Sharding-JDBC、配置复杂 | 大型分布式系统、需要丰富分库分表功能的场景 |
| Sharding-Proxy | 支持多语言、动态扩容、统一管理分片规则 | 需独立部署、性能有损耗(代理层) | 多语言开发、需要统一管理分片规则的场景 |
五、总结
本文通过Spring Boot + MyBatis-Plus + Sharding-JDBC实现了水平分表、垂直分表、水平分库三个核心场景的实战,详细讲解了配置流程、示例代码和测试验证。分库分表的核心是"合理拆分"与"自动路由",开发者需根据业务场景选择合适的拆分方式和分片键,同时注意事务处理、热点数据等问题。
MyBatis-Plus的增强功能(如BaseMapper、条件构造器)与Sharding-JDBC无缝集成,大大降低了分库分表的开发成本。在实际项目中,还需结合业务需求选择合适的中间件,并做好性能监控和动态扩容方案,确保系统稳定运行。