跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
Javajava

Spring Boot 结合 MyBatis-Plus 实现分库分表实战

综述由AI生成介绍在 Spring Boot 项目中利用 MyBatis-Plus 和 Sharding-JDBC 实现数据库分库分表的方案。涵盖水平分表、垂直分表及水平分库三种场景,详细讲解了配置文件编写、实体类映射、Mapper 接口设计及测试验证流程。同时补充了分片键选择、事务处理及中间件对比等进阶知识,帮助开发者解决单库单表性能瓶颈问题。

片刻发布于 2026/3/30更新于 2026/6/326 浏览
Spring Boot 结合 MyBatis-Plus 实现分库分表实战

Spring Boot 数据持久化:MyBatis-Plus 分库分表实战指南

在分布式系统开发中,随着业务规模的扩大,单库单表的架构往往会面临性能瓶颈——数据量激增导致查询缓慢、写入耗时变长,甚至出现表锁阻塞等问题。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 Boot2.7.10稳定版,适配大多数中间件
MyBatis-Plus3.5.3.1支持 Sharding-JDBC 的增强功能
Sharding-JDBC4.1.1轻量级分库分表中间件
MySQL8.0.x关系型数据库(示例用)
Lombok1.18.24简化实体类代码(可选)

2.2 依赖引入(pom.xml)

在 Spring Boot 项目中引入核心依赖,重点是 MyBatis-Plus Starter 和 Sharding-JDBC Starter:

<!-- 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. 水平分表场景:1 个数据库(sharding_db),2 张用户表(t_user_0、t_user_1),结构完全相同。
  2. 垂直分表场景:1 个数据库(sharding_db),2 张用户相关表(t_user_base、t_user_extend),结构不同。
  3. 水平分库场景:2 个数据库(sharding_db_0、sharding_db_1),每个库各 1 张订单表(t_order),结构完全相同。

创建 SQL 示例(以 MySQL 为例):

-- 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)
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)
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 方法,直接继承即可:

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)

通过测试验证数据是否按规则路由到对应表:

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 对应不同的表:

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)
// 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)
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 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 中添加方法:

Map<String, Object> selectUserFullInfo(Long id);
3.2.5 测试类
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)

水平分库需配置多个数据源,并指定数据库分片规则和表分片规则(本例表不分片,仅库分片):

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)
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)
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 测试类
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 无缝集成,大大降低了分库分表的开发成本。在实际项目中,还需结合业务需求选择合适的中间件,并做好性能监控和动态扩容方案,确保系统稳定运行。

目录

  1. Spring Boot 数据持久化:MyBatis-Plus 分库分表实战指南
  2. 一、分库分表核心概念:为什么需要它?
  3. 1.1 分库 vs 分表
  4. 1.2 拆分方式:水平 vs 垂直
  5. 水平拆分(横向拆分)
  6. 垂直拆分(纵向拆分)
  7. 二、实战准备:技术栈与环境搭建
  8. 2.1 技术栈版本
  9. 2.2 依赖引入(pom.xml)
  10. 2.3 数据库准备
  11. 三、核心实战:MyBatis-Plus 分库分表示例
  12. 场景 1:水平分表(按用户 ID 取模拆分)
  13. 3.1.1 配置文件(application.yml)
  14. Sharding-JDBC 配置
  15. MyBatis-Plus 配置
  16. 3.1.2 实体类(User.java)
  17. 3.1.3 Mapper 接口(UserMapper.java)
  18. 3.1.4 测试类(UserMapperTest.java)
  19. 3.1.5 测试结果说明
  20. 场景 2:垂直分表(按字段维度拆分)
  21. 3.2.1 配置文件(application.yml)
  22. MyBatis-Plus 配置(不变)
  23. 3.2.2 实体类(UserBase.java + UserExtend.java)
  24. 3.2.3 Mapper 接口(UserBaseMapper.java + UserExtendMapper.java)
  25. 3.2.4 关联查询(自定义 XML)
  26. 3.2.5 测试类
  27. 场景 3:水平分库(按用户 ID 取模拆分数据库)
  28. 3.3.1 配置文件(application.yml)
  29. MyBatis-Plus 配置(不变)
  30. 3.3.2 实体类(Order.java)
  31. 3.3.3 Mapper 接口(OrderMapper.java)
  32. 3.3.4 测试类
  33. 四、拓展知识点:分库分表进阶技巧
  34. 4.1 分片键选择技巧
  35. 4.2 分库分表后的事务处理
  36. 4.3 MyBatis-Plus 高级特性适配
  37. 4.4 分库分表中间件对比
  38. 五、总结
  • 💰 8折买阿里云服务器限时8折了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 🤖 一键搭建Deepseek满血版了解详情
  • 一键打造专属AI 智能体了解详情
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • 模拟算法详解:竞赛常用题型与代码实现
  • Python 实现 MCP 客户端调用高德地图天气查询示例
  • Stable Diffusion v4.10 与 ComfyUI 整合包使用指南
  • Material Files:Android 开源文件管理器深度体验
  • Dify 工作流发布为 MCP Server 实战指南
  • 从零搭建 Django + Vue 全栈应用:用户认证篇
  • AI 大模型通信机制:流式传输与数据封装逻辑解析
  • OpenClaw 本地部署及飞书机器人接入实战指南
  • 阿里开源 PageAgent:用自然语言操控网页的纯前端智能体框架
  • 网络安全常见设备及其功能作用详解
  • 无人机视觉任务常用数据集汇总:检测与分割资源整理
  • Nginx 高性能 Web 服务器架构与配置指南
  • Whisper v0.2 本地语音转文字工具安装与使用指南
  • LangChain 框架核心模块与使用指南
  • AI 需求预测的局限与 Python 开发者的心理洞察实践
  • Clawdbot 飞书机器人配置与集成实战
  • 滑动窗口算法详解与经典例题实战
  • FPGA 摄像头采集与 HDMI 显示实战:OV5640 驱动及 Verilog 实现
  • 模型预测控制(MPC)算法原理及仿真搭建
  • 阿里开源 Page-Agent:一行代码实现浏览器内 AI 原生应用

相关免费在线工具

  • Keycode 信息

    查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online

  • Escape 与 Native 编解码

    JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online

  • JavaScript / HTML 格式化

    使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online

  • JavaScript 压缩与混淆

    Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online