SpringBoot与MyBatis-Plus整合实战:从零构建高效数据层开发
1. 项目概述:为什么是SpringBoot + MyBatis-Plus?
如果你正在用Java做Web开发,尤其是企业级应用的后端,那么SpringBoot和MyBatis-Plus这对组合,大概率是你绕不开的技术栈。SpringBoot以其“约定大于配置”的理念,极大地简化了Spring应用的初始搭建和开发过程。而MyBatis-Plus(简称MP)作为MyBatis的增强工具,在保留MyBatis所有特性的基础上,提供了大量开箱即用的功能,比如强大的CRUD操作、分页、性能分析、代码生成器等。
把它们俩整合在一起,目的非常明确:用最少的配置和代码,实现最高效、最规范的数据层开发。这不仅仅是“能用”,而是追求一种“优雅”和“高效”。想象一下,你不再需要为每一个实体类手写增删改查的SQL,分页查询只需要几行配置,复杂的条件查询可以用Lambda表达式优雅地构建,甚至连基础的Service层代码都可以自动生成。这就是整合带来的直接价值——将开发者从重复、繁琐的“体力劳动”中解放出来,更专注于核心业务逻辑的实现。
这篇文章,我会从一个有多年实战经验的开发者角度,带你从零开始,完成一次“超详细”的整合。不仅仅是把依赖配上去、把Demo跑通,更重要的是,我会拆解每一步背后的考量,分享在实际项目中如何配置更稳妥,以及那些官方文档可能不会明说,但踩过坑才知道的“潜规则”。无论你是刚接触这个组合的新手,还是想优化现有项目的老手,相信都能找到有用的东西。
2. 环境准备与项目初始化
在开始敲代码之前,搭建一个干净、标准化的开发环境是第一步。这能避免很多因环境不一致导致的诡异问题。
2.1 开发工具与依赖选择
我个人的主力IDE是IntelliJ IDEA Ultimate版,它对SpringBoot的支持堪称完美。当然,如果你习惯使用Eclipse或VS Code配合相应插件,也完全没问题。关键在于项目管理工具:强烈推荐使用Maven或Gradle。这里我以Maven为例,因为它在国内的生态和认知度更广。
创建一个SpringBoot项目有多种方式:
- 通过IDEA的Spring Initializr:这是最直观的方式。在新建项目时选择“Spring Initializr”,它本质上是一个图形化的 start.spring.io 。
- 通过官方网页 start.spring.io:你可以直接在网页上勾选依赖,生成项目压缩包,再导入IDE。这种方式更灵活,不受IDE限制。
- 手动搭建:对于想深入了解项目结构的老手,可以创建一个普通的Maven项目,然后手动添加SpringBoot的父POM和依赖。
对于新手,我推荐第一种方式。在IDEA的Spring Initializr界面,你需要关注几个关键选择:
- Project:Maven Project。
- Language:Java。
- Spring Boot:选择一个稳定的版本,如
3.2.x或3.1.x。SpringBoot 3.x需要Java 17+,如果你的环境是Java 8,则需要选择SpringBoot 2.7.x(官方已停止功能更新,仅维护)。本文基于SpringBoot 3.x和Java 17。 - Project Metadata:填写你的
Group(组织标识,如com.example)、Artifact(项目标识,如demo)和Package name(包名)。 - Dependencies:这是核心。我们需要添加:
Spring Web:用于构建Web应用。MySQL Driver:数据库驱动,根据你用的数据库选择。MyBatis Framework:注意,这里只选这个!不要选成“MyBatis Plus”。因为MyBatis-Plus的依赖我们需要手动在pom.xml里添加,以控制其版本。
点击创建后,IDEA会为你生成一个标准的SpringBoot项目结构。
2.2 关键依赖的POM文件配置
项目创建好后,打开pom.xml文件。Spring Initializr已经为我们添加了SpringBoot父工程和基本的依赖。现在,我们需要手动添加MyBatis-Plus的依赖。
找到<dependencies>部分,在已有依赖的基础上,添加如下内容:
<dependencies> <!-- Spring Initializr 生成的依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>com.mysql</groupId> <artifactId>mysql-connector-j</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>3.0.3</version> <!-- 版本需与SpringBoot 3.x匹配 --> </dependency> <!-- 手动添加:MyBatis-Plus 核心依赖 --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.5.5</version> <!-- 请使用当前最新稳定版 --> </dependency> <!-- 其他常用工具 --> <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> </dependencies>关键点解析:
- 版本对齐:
mybatis-spring-boot-starter的版本必须与你的SpringBoot大版本兼容。SpringBoot 3.x通常对应3.0.x版本。mybatis-plus-boot-starter的版本建议使用官方仓库中的最新稳定版。 - 依赖关系:
mybatis-plus-boot-starter已经包含了mybatis-spring-boot-starter和MyBatis的核心依赖。但上面我们依然显式声明了mybatis-spring-boot-starter,这是为了更清晰地控制版本,避免传递依赖可能带来的冲突。这是一种更稳妥的做法。 - Lombok:这是一个非必需但强烈推荐的工具。它通过注解自动生成Getter、Setter、构造函数等代码,能让实体类非常简洁。记得在IDEA中安装Lombok插件并启用注解处理。
注意:依赖添加后,记得点击Maven工具栏的刷新按钮,让IDEA下载相关的Jar包。如果网络不好导致下载失败,可以检查Maven配置的镜像仓库是否为国内源(如阿里云镜像)。
3. 核心配置详解与最佳实践
配置是整合的灵魂,合理的配置能让后续开发事半功倍,也能避免很多运行时错误。
3.1 数据库连接与MyBatis-Plus基础配置
首先,在src/main/resources/application.yml(或application.properties)中配置数据库连接和MyBatis-Plus的基本参数。我更喜欢YAML格式,因为结构更清晰。
# 应用服务端口 server: port: 8080 # 数据源配置 spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/your_database?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai username: root password: your_password # MyBatis-Plus 配置 mybatis-plus: configuration: # 控制台打印完整带参数SQL(仅开发环境开启) log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 开启驼峰命名自动映射。数据库字段 user_name 会自动映射到实体属性 userName map-underscore-to-camel-case: true # 配置默认的执行器。REUSE 执行器会重用预处理语句,性能较好,是默认推荐值 default-executor-type: reuse global-config: db-config: # 全局逻辑删除字段名(需与实体类注解对应) logic-delete-field: deleted # 逻辑已删除值(默认为 1) logic-delete-value: 1 # 逻辑未删除值(默认为 0) logic-not-delete-value: 0 # 全局表前缀(如果所有表都有共同前缀,如 `t_`) # table-prefix: t_ # 主键类型。AUTO 为数据库自增,INPUT 为手动输入,ASSIGN_ID 为雪花算法,ASSIGN_UUID 为UUID id-type: ASSIGN_ID # 指定Mapper XML文件的位置。如果SQL写在XML里,需要配置。如果全用注解或MP自带方法,可不配。 mapper-locations: classpath*:/mapper/**/*.xml # 配置类型别名包,这样在XML里可以直接写类名,不用写全限定名 type-aliases-package: com.example.demo.entity配置项深度解读:
log-impl: StdOutImpl:这是开发阶段的神器。它会将MyBatis执行的SQL语句及其参数完整地打印到控制台,方便你调试和检查SQL是否正确。切记,在生产环境一定要关闭此配置,可以设置为org.apache.ibatis.logging.nologging.NoLoggingImpl或使用更专业的日志框架(如SLF4J+Logback)来控制日志级别。map-underscore-to-camel-case: true:这是连接数据库命名习惯(下划线)和Java命名习惯(驼峰)的桥梁。强烈建议开启,能省去大量@TableField注解。id-type: ASSIGN_ID:这是MyBatis-Plus雪花算法的主键生成策略。即使数据库主键是自增(AUTO),在插入数据前,实体对象的Id字段也会被预先填充一个雪花算法ID。这有利于在分布式环境下保持ID全局唯一。如果你完全依赖数据库自增,就设为AUTO。logic-delete-field:逻辑删除配置。这代表你希望用一个字段(如deleted)来标记数据是否被删除,而不是物理删除。配置后,MP自带的delete方法会自动变为更新deleted字段,select方法会自动加上deleted=0的条件。这是一个极其好用的生产特性。
3.2 实体类、Mapper与Service的创建规范
配置好后,我们开始创建核心的三层结构:实体类(Entity)、数据访问层(Mapper)、服务层(Service)。MyBatis-Plus为每一层都提供了强大的基类支持。
1. 实体类 (Entity)在com.example.demo.entity包下创建User.java。
package com.example.demo.entity; import com.baomidou.mybatisplus.annotation.*; import lombok.Data; import java.time.LocalDateTime; @Data // Lombok注解,生成getter, setter, toString等 @TableName("sys_user") // 指定对应数据库表名,如果表名和类名一致(忽略大小写和下划线),可省略 public class User { /** * 主键 * ASSIGN_ID:使用雪花算法生成ID(默认) * 如果数据库是自增,可以用 @TableId(type = IdType.AUTO) */ @TableId(type = IdType.ASSIGN_ID) private Long id; private String username; private String password; private String email; /** * 字段填充策略。插入时自动填充当前时间 */ @TableField(fill = FieldFill.INSERT) private LocalDateTime createTime; /** * 字段填充策略。插入和更新时自动填充当前时间 */ @TableField(fill = FieldFill.INSERT_UPDATE) private LocalDateTime updateTime; /** * 逻辑删除标记。需要配合全局配置使用 * @TableLogic 注解优先级高于全局配置 */ @TableLogic private Integer deleted; // 对应全局配置的 logic-delete-field }2. Mapper接口在com.example.demo.mapper包下创建UserMapper.java。它只需要继承MyBatis-Plus提供的BaseMapper接口,并指定泛型为实体类。
package com.example.demo.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.example.demo.entity.User; import org.apache.ibatis.annotations.Mapper; @Mapper // 这个注解很重要,让Spring知道这是一个MyBatis Mapper。也可以在启动类加 @MapperScan 批量扫描 public interface UserMapper extends BaseMapper<User> { // 此时,你已经拥有了针对User表的CRUD方法,无需编写任何XML或注解SQL // 例如:insert, deleteById, updateById, selectById, selectList, selectPage, selectMaps, ... }3. Service接口与实现在com.example.demo.service包下创建IUserService.java接口和UserServiceImpl.java实现类。MP同样提供了Service层的增强。
// IUserService.java package com.example.demo.service; import com.baomidou.mybatisplus.extension.service.IService; import com.example.demo.entity.User; public interface IUserService extends IService<User> { // 可以在此定义一些复杂的、非通用的业务查询方法 User getByUsername(String username); }// UserServiceImpl.java package com.example.demo.service.impl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.example.demo.entity.User; import com.example.demo.mapper.UserMapper; import com.example.demo.service.IUserService; import org.springframework.stereotype.Service; @Service // 注册为Spring Bean public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService { @Override public User getByUsername(String username) { // 这里演示一个自定义查询。可以使用baseMapper(即UserMapper)调用其方法 // 也可以使用lambdaQuery()这种更优雅的方式 return this.lambdaQuery() .eq(User::getUsername, username) .one(); // 查询一条记录 } }核心优势体现:通过继承BaseMapper和IService,你的UserMapper和IUserService瞬间获得了数十个通用的数据操作方法,完全不需要你写一句SQL。这是整合带来的最直接的效率提升。
4. 核心功能实战与高级特性
基础架子搭好了,我们来实际使用它,并探索一些高级、实用的特性。
4.1 基础CRUD与条件构造器使用
让我们在Controller里快速测试一下CRUD。创建UserController.java。
package com.example.demo.controller; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.example.demo.entity.User; import com.example.demo.service.IUserService; 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 IUserService userService; // 1. 新增 @PostMapping public boolean saveUser(@RequestBody User user) { // MP会自动处理主键(如果配置了ASSIGN_ID)和字段填充(如createTime) return userService.save(user); } // 2. 根据ID查询 @GetMapping("/{id}") public User getById(@PathVariable Long id) { return userService.getById(id); } // 3. 条件查询:使用LambdaQueryWrapper(推荐,防误写) @GetMapping("/list") public List<User> listUsers(@RequestParam(required = false) String username, @RequestParam(required = false) String email) { LambdaQueryWrapper<User> wrapper = Wrappers.lambdaQuery(); if (username != null && !username.isEmpty()) { wrapper.like(User::getUsername, username); // 模糊查询 username like '%?%' } if (email != null && !email.isEmpty()) { wrapper.eq(User::getEmail, email); // 等值查询 } wrapper.orderByDesc(User::getCreateTime); // 按创建时间倒序 return userService.list(wrapper); } // 4. 更新 @PutMapping public boolean updateUser(@RequestBody User user) { // updateById 会根据主键更新非空字段 return userService.updateById(user); } // 5. 逻辑删除(配置了逻辑删除后,调用removeById实际是更新deleted字段) @DeleteMapping("/{id}") public boolean deleteUser(@PathVariable Long id) { return userService.removeById(id); } }条件构造器(Wrapper)详解: 这是MyBatis-Plus的灵魂功能之一。它让你用Java代码的方式,安全、优雅地构建查询条件。上面用的是LambdaQueryWrapper,它通过方法引用(如User::getUsername)来指定字段,避免了硬编码字符串可能带来的拼写错误。还有QueryWrapper,使用字符串列名,在某些动态SQL场景下更灵活。
4.2 分页查询的标准化实现
分页是Web应用中最常见的需求。MyBatis-Plus的分页插件需要显式配置。
1. 配置分页插件创建一个配置类MybatisPlusConfig.java。
package com.example.demo.config; import com.baomidou.mybatisplus.annotation.DbType; import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class MybatisPlusConfig { @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); // 添加分页插件,并指定数据库类型(这里是MySQL) interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); // 还可以添加其他插件,如乐观锁插件 // interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor()); return interceptor; } }2. 使用分页查询修改或新增Controller方法。
// 在UserController中添加 import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; @GetMapping("/page") public IPage<User> pageUsers(@RequestParam(defaultValue = "1") Long current, @RequestParam(defaultValue = "10") Long size) { // 1. 创建分页对象。current: 当前页,size: 每页大小 Page<User> page = new Page<>(current, size); // 2. 可以添加查询条件 LambdaQueryWrapper<User> wrapper = Wrappers.lambdaQuery(); wrapper.orderByDesc(User::getCreateTime); // 3. 执行分页查询。page对象会被填充总记录数、分页记录列表等信息 return userService.page(page, wrapper); }调用/user/page?current=2&size=5,返回的结果不仅包含第2页的5条数据,还包含total(总记录数)、pages(总页数)等分页信息,前端可以直接使用。
4.3 自动填充与乐观锁实战
自动填充:我们之前在实体类中用@TableField(fill = FieldFill.INSERT)标注了createTime和updateTime。现在需要实现一个处理器来告诉MP如何填充。
创建处理器MyMetaObjectHandler.java:
package com.example.demo.handler; import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; import org.apache.ibatis.reflection.MetaObject; import org.springframework.stereotype.Component; import java.time.LocalDateTime; @Component // 注册为Spring组件 public class MyMetaObjectHandler implements MetaObjectHandler { @Override public void insertFill(MetaObject metaObject) { // 插入时,为有 @TableField(fill = FieldFill.INSERT) 注解的字段填充值 this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now()); this.strictInsertFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now()); // 还可以填充其他字段,如操作人ID等 // this.strictInsertFill(metaObject, "createBy", Long.class, UserContext.getCurrentUserId()); } @Override public void updateFill(MetaObject metaObject) { // 更新时,为有 @TableField(fill = FieldFill.INSERT_UPDATE) 或 FieldFill.UPDATE 的字段填充值 this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now()); } }乐观锁:用于解决并发更新问题。假设我们给User表加一个version字段。
- 在
User实体类中添加字段并加上@Version注解。@Version private Integer version; - 在
MybatisPlusConfig配置类中,将乐观锁插件注释打开。interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor()); - 更新数据时,MP会自动带上
version条件。例如:update user set name=?, version=? where id=? and version=?。如果版本号不匹配,更新行数为0,你可以在业务层判断并处理更新失败的情况(如重试或提示用户)。
5. 进阶技巧与生产环境考量
当项目从Demo走向生产,一些进阶配置和考量就变得至关重要。
5.1 多数据源与动态表名
多数据源:一个项目连接多个数据库。SpringBoot官方不直接提供多数据源支持,但可以通过配置多个DataSource、SqlSessionFactory和TransactionManager来实现。MyBatis-Plus有一个第三方扩展dynamic-datasource-spring-boot-starter可以简化这一过程。其核心思路是使用注解@DS(“数据源名称”)在Service或Mapper方法上切换数据源。引入该依赖后,配置会变得相对简单,但需要仔细处理事务边界问题。
动态表名:例如,按月份分表的场景。MyBatis-Plus提供了ITableNameHandler接口。你可以实现这个接口,根据当前线程上下文或参数动态返回表名。然后在配置中将其设置为全局表名处理器。这通常用于日志表、流水表等数据量巨大且按时间分割的场景。
5.2 代码生成器:效率倍增器
对于拥有大量表的项目,手动创建Entity、Mapper、Service、Controller是非常枯燥的。MyBatis-Plus提供了一个强大的代码生成器(AutoGenerator)。
你可以编写一个简单的生成器主类,配置好数据源、包路径、策略(是否生成Controller、Service等)、模板引擎(默认Velocity),运行一次即可生成所有基础代码。这能节省你80%以上的重复劳动。生成的代码风格统一,且已经集成了MP的基类,开箱即用。这是中大型项目必备的利器。官方文档有详细示例,核心是配置DataSourceConfig、PackageConfig、StrategyConfig和TemplateConfig。
5.3 性能监控与SQL优化建议
- 关闭开发日志:如前所述,生产环境务必关闭
mybatis-plus.configuration.log-impl的控制台输出,或将其级别设为DEBUG并通过日志框架控制。 - 使用P6Spy或Log4j2格式化输出:如果你在生产环境仍需监控SQL(通常只在特定排查时开启),可以使用P6Spy这类第三方组件,它能输出格式化、可读性更强的SQL,并记录执行时间。
- 警惕N+1查询问题:这是ORM框架的通病。当你使用MP查询出一个列表(N条),然后循环遍历每条数据去查询其关联对象时,就会产生N+1条SQL。解决方案是:
- 一次查询,手动组装:先查询主列表,收集所有关联ID,再用
in语句一次查出所有关联数据,在内存中通过Map进行组装。 - 使用MyBatis的
<collection>或<association>:在XML中编写包含JOIN的复杂SQL,实现结果映射。这超出了MP通用Mapper的范畴,需要回归到MyBatis本身。 - 使用MP的
@TableField(exist = false)+自定义查询方法:在实体类中定义非数据库字段,并提供一个自定义的Mapper方法,用一条SQL查询出所有需要的数据并手动填充到这些字段中。
- 一次查询,手动组装:先查询主列表,收集所有关联ID,再用
- 合理使用索引:MP生成的SQL条件顺序,取决于你使用
Wrapper添加条件的顺序。确保你的查询条件能够命中数据库索引。对于复合索引,要特别注意条件的顺序。
6. 常见问题排查与实战心得
整合过程很少一帆风顺,这里记录几个我踩过的坑和解决方案。
6.1 启动报错与依赖冲突
- 问题:启动时报
java.lang.ClassNotFoundException: org.mybatis.logging.LoggerFactory或类似关于MyBatis的类找不到。 - 排查:这通常是依赖冲突或版本不匹配。运行
mvn dependency:tree命令查看依赖树,检查是否有多个不同版本的mybatis或mybatis-spring被引入。SpringBoot的spring-boot-starter-*系列依赖会管理其内部组件的版本,但手动添加的依赖可能会打破这种管理。 - 解决:
- 确保
mybatis-plus-boot-starter的版本与你的SpringBoot版本兼容。 - 在
pom.xml中,对冲突的依赖使用<exclusions>标签排除掉低版本或不需要的传递依赖。 - 统一使用MyBatis-Plus的BOM(Bill of Materials)进行版本管理,这是最推荐的方式。
- 确保
6.2 字段映射失败与空值问题
- 问题:查询结果中,某个字段始终为
null,但数据库里有值。 - 排查:
- 首先检查
application.yml中的map-underscore-to-camel-case是否设置为true。如果字段是user_name,实体属性是userName,这个配置必须开启。 - 如果字段名和属性名不一致(例如数据库字段
is_admin,Java属性admin),需要使用@TableField("is_admin")进行显式映射。 - 检查实体类属性的类型是否与数据库字段类型匹配。例如,数据库是
datetime,Java用LocalDateTime;数据库是tinyint(1),Java用Boolean。
- 首先检查
- 问题:使用
updateById更新时,想把某个字段更新为null,但执行后数据库里该字段没变。 - 解决:MP的默认更新策略是“非空更新”。即,实体对象中为
null的字段,不会参与到UPDATE语句的SET部分。如果你想将字段更新为null,有两种方式:- 使用
UpdateWrapper:new UpdateWrapper<User>().set("email", null).eq("id", 1)。 - 在实体类字段上加上注解
@TableField(strategy = FieldStrategy.IGNORED),但这样会全局忽略该字段的空值判断,需谨慎。
- 使用
6.3 分页插件失效与总数查询慢
- 问题:调用了
page方法,但返回的IPage对象里records是全部数据,total也是错的,好像没分页。 - 排查:
- 没有配置分页插件:这是最常见的原因。确保
MybatisPlusConfig配置类被Spring扫描到,并且MybatisPlusInterceptor中加入了PaginationInnerInterceptor。 - 存在多个
SqlSessionFactory或MybatisPlusInterceptor:在多数据源等复杂配置下,可能无意中覆盖了配置。
- 没有配置分页插件:这是最常见的原因。确保
- 问题:分页查询
count语句(查询总数)非常慢,尤其是在大表且条件复杂时。 - 优化:
- 自定义
count查询:MP允许你为分页查询指定一个优化的count语句。可以通过创建XML文件,定义一个id为方法名_COUNT的查询来实现。例如,Mapper方法叫selectUserPage,那么可以定义一个selectUserPage_COUNT的查询。 - 关闭
count查询:如果业务上不需要知道总条数(例如手机端无限滚动加载),可以在创建Page对象时,传入第三个参数false:new Page<>(current, size, false)。这样就不会执行count语句。 - 数据库层面优化:为
count查询涉及的where条件字段建立合适的索引。
- 自定义
6.4 事务管理须知
SpringBoot默认集成了Spring的事务管理。在Service层的方法上使用@Transactional注解即可声明事务。但需要注意:
- MyBatis-Plus的Service方法:诸如
save,updateById,removeById等方法,内部并没有添加@Transactional。如果你在一个非事务方法内连续调用多个这样的方法,每个方法都会是一个独立的事务。如果需要原子性,需要在调用它们的Service方法上添加@Transactional。 - Lambda查询与事务:
lambdaQuery(),lambdaUpdate()等链式调用本身不涉及事务。事务边界仍然由你添加的@Transactional注解决定。 - 多数据源事务:这是一个复杂话题。标准的
@Transactional只能管理一个数据源。如果需要跨数据源的分布式事务,需要考虑使用JTA、Seata等分布式事务解决方案,这超出了基础整合的范围。
整合SpringBoot和MyBatis-Plus,本质上是在SpringBoot的自动化配置基础上,引入MP的一系列增强约定和工具。核心思想是“配置化”和“约定优于配置”。把基础的连接、事务、映射交给框架,开发者聚焦在业务逻辑和那些框架无法自动生成的复杂SQL上。从简单的CRUD到动态数据源,从代码生成到性能优化,这套组合拳能覆盖从创业项目到大型企业应用的绝大多数场景。关键在于,你要理解每一层配置和注解背后的意图,这样才能在遇到问题时快速定位,在需要扩展时游刃有余。