JDK 17与Spring Boot 3环境下MyBatisPlus整合实战与避坑指南
2026/8/20 8:20:04 网站建设 项目流程

如果你正在使用 JDK 17 和 Spring Boot 3 开发新项目,并且还在纠结于 MyBatis 繁琐的 XML 配置和样板代码,那么这篇文章就是为你准备的。很多开发者以为,在 Spring Boot 3 这个“新世界”里,MyBatisPlus 只是简单地换个版本号就能跑起来,但实际上一脚踩进去,你会发现从依赖冲突、配置失效到新特性不兼容,处处是坑。本文的核心判断是:MyBatisPlus 与 Spring Boot 3 的整合,绝不仅仅是版本升级,而是一次涉及依赖管理、配置范式、新特性适配的“系统性迁移”。盲目照搬旧项目的配置,大概率会让你在启动阶段就卡住。

读完本文,你将能清晰地知道如何从零开始,在 JDK 17 + Spring Boot 3 的环境下,正确、高效地整合 MyBatisPlus,并避开那些常见的“版本陷阱”。我们会从环境搭建、核心配置、代码生成,一直讲到分页、枚举映射、字段加解密等高级特性,确保你不仅能跑通 Demo,更能理解背后的原理,应用到实际生产项目中。

1. 为什么是 JDK 17 + Spring Boot 3 + MyBatisPlus?

在开始动手之前,我们需要先理解这个技术栈组合的价值和挑战。这不是一个随意的选择,而是面向未来的技术决策。

JDK 17是一个长期支持(LTS)版本,带来了诸如密封类、模式匹配、新的垃圾收集器等语言和性能层面的增强。对于企业级应用,选择 LTS 版本意味着更稳定的支持和更长的维护周期。

Spring Boot 3是一个里程碑式的版本,它基于 Spring Framework 6,最低要求 JDK 17。它带来了全新的“Problem Details”错误处理机制、更完善的 GraalVM 原生镜像支持、以及将javax命名空间全面迁移到jakarta等重大变化。后者是整合 MyBatisPlus 时最需要关注的兼容性问题。

MyBatisPlus是一个强大的 MyBatis 增强工具,提供了通用的 Mapper、Service CRUD 接口、条件构造器、分页插件等功能,能极大提升数据层开发效率。然而,它的很多自动配置和插件依赖于 Spring Boot 的特定版本。

核心挑战:MyBatisPlus 的早期版本(如 3.4.x, 3.5.x)是为 Spring Boot 2.x 和javax包设计的。直接用在 Spring Boot 3 上,会因为javax->jakarta的迁移而导致类找不到(如javax.servlet.*),或与 Spring Boot 3 内部的新机制不兼容。

因此,我们的首要任务是选择正确的 MyBatisPlus 版本。根据官方仓库和社区实践,MyBatisPlus 3.5.3.1 及以上版本开始提供对 Spring Boot 3 的初步支持,而最新的稳定版本(如 3.5.7)则提供了更完善的兼容性。本文将基于 MyBatisPlus 3.5.7 进行演示。

2. 环境准备与项目初始化

在开始编码前,确保你的开发环境已就绪。这是后续所有步骤的基础。

2.1 基础环境清单

  • JDK: 17 或更高版本(推荐 Oracle OpenJDK 17 或 Amazon Corretto 17)。
  • IDE: IntelliJ IDEA (2023.3+ 版本对 Spring Boot 3 支持更好) 或 Eclipse (需安装 Spring Tools)。
  • 构建工具: Maven (3.6+) 或 Gradle (7.6+)。本文使用 Maven。
  • 数据库: 任意(MySQL 8.0、PostgreSQL 等)。本文以 MySQL 8.0 为例。

2.2 使用 Spring Initializr 快速创建项目

最稳妥的方式是通过 start.spring.io 生成项目骨架。

  1. 访问 start.spring.io。
  2. 选择以下配置:
    • Project: Maven Project
    • Language: Java
    • Spring Boot: 3.2.5 (选择最新的稳定版)
    • Project Metadata: 根据你的情况填写 Group、Artifact 等信息。
    • Packaging: Jar
    • Java: 17
  3. Dependencies中,先添加:
    • Spring Web(用于构建Web应用)
    • MySQL Driver(数据库驱动)
    • Lombok(简化实体类代码,可选但推荐)
  4. 点击Generate下载项目压缩包,并导入到你的 IDE 中。

此时,你得到了一个纯净的 Spring Boot 3 项目。接下来,我们需要手动添加 MyBatisPlus 的依赖。

2.3 关键依赖配置(pom.xml)

打开项目中的pom.xml文件,在<dependencies>部分添加 MyBatisPlus 的 Starter 依赖。

核心要点:必须使用与 Spring Boot 3 兼容的mybatis-plus-boot-starter版本。不要引入旧的mybatis-plus-boot-starter

<!-- 在已有的 dependencies 标签内添加 --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.5.7</version> <!-- 关键:使用兼容 Spring Boot 3 的版本 --> </dependency> <!-- 数据库驱动 (如果Initializr已添加,则无需重复) --> <dependency> <groupId>com.mysql</groupId> <artifactId>mysql-connector-j</artifactId> <scope>runtime</scope> </dependency> <!-- Lombok (如果Initializr已添加,则无需重复) --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency>

依赖冲突排查:添加依赖后,建议执行mvn dependency:tree命令,检查是否有低版本的 MyBatis 或其它冲突的依赖被传递进来。Spring Boot 3 默认管理 MyBatis 的版本,而 MyBatisPlus Starter 会覆盖它,这通常是良性的。

3. 核心配置详解:连接数据库与 MyBatisPlus

配置是整合的关键环节。Spring Boot 3 的配置方式与 2.x 基本一致,但属性前缀和默认值可能有细微差别。

3.1 数据库连接配置 (application.yml)

src/main/resources/application.yml中配置数据库连接。推荐使用 YAML 格式,因为它结构更清晰。

spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/mybatisplus_demo?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai username: root password: yourpassword # MyBatisPlus 相关配置 mybatis-plus: configuration: # 控制台打印完整带参数SQL(开发环境使用) log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 开启驼峰命名自动映射(数据库下划线字段 -> 实体类驼峰属性) map-underscore-to-camel-case: true global-config: db-config: # 全局主键类型:AUTO(数据库自增), INPUT(手动输入), ASSIGN_ID(雪花算法), ASSIGN_UUID(UUID) id-type: ASSIGN_ID # 逻辑删除字段名(非必须,按需配置) logic-delete-field: isDeleted # 逻辑已删除值(默认为 1) logic-delete-value: 1 # 逻辑未删除值(默认为 0) logic-not-delete-value: 0 # 指定 Mapper XML 文件位置(如果你有自定义的复杂SQL) mapper-locations: classpath*:/mapper/**/*.xml

配置解释

  • log-impl: StdOutImpl:这是排查 SQL 问题的利器。在开发阶段开启,可以清晰看到 MyBatisPlus 最终执行的 SQL 语句及其参数。生产环境务必关闭。
  • id-type: ASSIGN_ID:这是 MyBatisPlus 的推荐配置。它使用雪花算法生成分布式 ID,避免数据库自增 ID 在分库分表或数据迁移时的局限性。
  • 逻辑删除:通过配置一个字段(如is_deleted)来标记记录是否删除,而非物理删除。MyBatisPlus 会自动在查询中加上WHERE is_deleted=0条件,在删除操作时执行UPDATE SET is_deleted=1

3.2 主启动类与 Mapper 扫描

确保你的主启动类(通常是XxxApplication.java)上添加了@MapperScan注解,用于扫描 MyBatis 的 Mapper 接口。

// 文件路径:src/main/java/com/example/demo/DemoApplication.java package com.example.demo; import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication @MapperScan("com.example.demo.mapper") // 指定你的 Mapper 接口所在的包 public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } }

注意@MapperScan是 MyBatis 原生的注解,在mybatis-spring-boot-starter中。MyBatisPlus 的 Starter 包含了它,所以可以直接使用。如果忘记添加,启动时会报NoSuchBeanDefinitionException,提示找不到 Mapper 的 Bean。

4. 实体、Mapper 与 Service 的快速生成

MyBatisPlus 的核心魅力在于其强大的 CRUD 封装。我们通过一个User实体来演示。

4.1 创建实体类 (Entity)

使用 Lombok 简化代码。

// 文件路径:src/main/java/com/example/demo/entity/User.java package com.example.demo.entity; import com.baomidou.mybatisplus.annotation.*; import lombok.Data; import java.time.LocalDateTime; @Data @TableName("sys_user") // 指定表名,如果表名与类名一致(忽略大小写和下划线)可省略 public class User { /** * 主键 * @TableId 注解用于标识主键 * type = IdType.ASSIGN_ID 表示使用雪花算法生成ID */ @TableId(type = IdType.ASSIGN_ID) private Long id; /** * 用户名 */ private String username; /** * 密码 */ private String password; /** * 邮箱 */ private String email; /** * 创建时间 * @TableField 注解用于配置字段与数据库列的映射关系 * fill = FieldFill.INSERT 表示在插入操作时自动填充 */ @TableField(fill = FieldFill.INSERT) private LocalDateTime createTime; /** * 更新时间 * fill = FieldFill.INSERT_UPDATE 表示在插入和更新操作时自动填充 */ @TableField(fill = FieldFill.INSERT_UPDATE) private LocalDateTime updateTime; /** * 逻辑删除标记 (0-未删除, 1-已删除) * 需要配合全局配置 mybatis-plus.global-config.db-config.logic-delete-field 使用 */ @TableLogic private Integer isDeleted; }

注解说明

  • @TableName: 实体类对应的数据库表名。
  • @TableId: 主键注解。IdType.ASSIGN_ID是 MyBatisPlus 3.3.0 后推荐的分布式 ID 策略。
  • @TableField: 字段注解。fill属性配合元对象处理器(MetaObjectHandler)可以实现自动填充创建时间、更新时间等字段。
  • @TableLogic: 逻辑删除注解。标记此字段为逻辑删除标志位。

4.2 创建 Mapper 接口

Mapper 接口只需继承 MyBatisPlus 提供的BaseMapper,即可获得全套单表 CRUD 方法。

// 文件路径:src/main/java/com/example/demo/mapper/UserMapper.java package com.example.demo.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.example.demo.entity.User; public interface UserMapper extends BaseMapper<User> { // 无需编写任何方法,即可拥有 insert, selectById, updateById, deleteById, selectList 等方法。 // 如果需要复杂查询,可以在此处定义方法,并在 resources/mapper/UserMapper.xml 中编写SQL。 }

4.3 创建 Service 接口及其实现

Service 层可以继承IServiceServiceImpl,获得更丰富的批量操作和链式查询方法。

// 文件路径:src/main/java/com/example/demo/service/UserService.java package com.example.demo.service; import com.baomidou.mybatisplus.extension.service.IService; import com.example.demo.entity.User; public interface UserService extends IService<User> { // 可以在此定义业务特有的方法 // User getByUsername(String username); }
// 文件路径:src/main/java/com/example/demo/service/impl/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.UserService; import org.springframework.stereotype.Service; @Service // 不要忘记加@Service注解 public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService { // 如果 UserService 接口有自定义方法,需要在这里实现 // @Override // public User getByUsername(String username) { // return this.lambdaQuery().eq(User::getUsername, username).one(); // } }

至此,最基本的 CRUD 功能已经具备。你可以通过注入UserMapperUserService来操作User表。

5. 自动填充与元对象处理器

我们之前在User实体中定义了createTimeupdateTime的自动填充规则,现在需要实现MetaObjectHandler来定义填充的内容。

// 文件路径:src/main/java/com/example/demo/handler/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) { // 判断是否有 createTime 字段,且该字段值为空 if (metaObject.hasSetter("createTime")) { this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now()); } // 更新时间的插入填充 if (metaObject.hasSetter("updateTime")) { this.strictInsertFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now()); } } /** * 更新操作时自动填充 */ @Override public void updateFill(MetaObject metaObject) { // 判断是否有 updateTime 字段 if (metaObject.hasSetter("updateTime")) { this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now()); } } }

关键点strictInsertFillstrictUpdateFill是 MyBatisPlus 3.3.0 后推荐的方法,它们要求明确指定字段的Class类型,避免了类型推断错误。当执行userMapper.insert(user)userService.updateById(user)时,对应的时间字段会被自动填充为当前时间。

6. 核心功能实战:条件构造器与分页查询

MyBatisPlus 的条件构造器(QueryWrapper,LambdaQueryWrapper,UpdateWrapper)和分页插件是其最常用的高级功能。

6.1 条件构造器使用示例

假设我们需要查询邮箱包含 “example.com” 且创建时间在 2024 年之后的用户列表。

// 在 Service 或 Controller 中注入 UserService @Autowired private UserService userService; public void testQueryWrapper() { // 方式一:使用 LambdaQueryWrapper (推荐,类型安全,避免硬编码字段名) LambdaQueryWrapper<User> lambdaQuery = new LambdaQueryWrapper<>(); lambdaQuery.like(User::getEmail, "example.com") .ge(User::getCreateTime, LocalDateTime.of(2024, 1, 1, 0, 0)) .orderByDesc(User::getCreateTime); List<User> userList1 = userService.list(lambdaQuery); // 方式二:使用 QueryWrapper (字段名用字符串,灵活性高但容易写错) QueryWrapper<User> queryWrapper = new QueryWrapper<>(); queryWrapper.like("email", "example.com") .ge("create_time", LocalDateTime.of(2024, 1, 1, 0, 0)) .orderByDesc("create_time"); List<User> userList2 = userService.list(queryWrapper); // 链式调用 lambda 查询 (更简洁) List<User> userList3 = userService.lambdaQuery() .like(User::getEmail, "example.com") .ge(User::getCreateTime, LocalDateTime.of(2024, 1, 1, 0, 0)) .orderByDesc(User::getCreateTime) .list(); }

强烈推荐使用LambdaQueryWrapper,因为它通过方法引用来获取字段名,在编译期就能检查错误,重构代码时也更安全。

6.2 分页插件配置与使用

MyBatisPlus 的分页功能需要先配置一个分页插件(Interceptor)。

// 文件路径:src/main/java/com/example/demo/config/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 { /** * 添加 MyBatisPlus 插件 * 注意:在 Spring Boot 3 中,旧版的 PaginationInterceptor 已废弃,必须使用 MybatisPlusInterceptor */ @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); // 添加分页插件,并指定数据库类型(这里是MySQL) interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); // 还可以添加其他插件,如乐观锁插件 // interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor()); return interceptor; } }

配置好插件后,就可以在 Service 或 Mapper 中使用分页查询了。

public void testPagination() { // 构建分页参数:查询第1页,每页10条 Page<User> page = new Page<>(1, 10); // 构建查询条件 LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.isNotNull(User::getEmail); // 执行分页查询 Page<User> resultPage = userService.page(page, queryWrapper); // 获取分页数据 List<User> records = resultPage.getRecords(); // 当前页数据列表 long total = resultPage.getTotal(); // 总记录数 long pages = resultPage.getPages(); // 总页数 long current = resultPage.getCurrent(); // 当前页码 long size = resultPage.getSize(); // 每页大小 System.out.println("总记录数: " + total); System.out.println("当前页数据: " + records); }

关于“单页500条限制”:这是一个常见的误解。MyBatisPlus 分页插件本身没有硬性限制。所谓的“500条限制”通常来自前端或 API 网关的配置,或者开发者自己出于性能考虑在业务代码中做的限制。如果你需要查询大量数据,应使用Page对象正常分页,或者考虑使用limit进行流式查询。插件只是帮你把Page对象转换为数据库的LIMIT语句。

7. 高级特性:枚举映射与字段加解密

7.1 枚举映射

将数据库的 tinyint 或 varchar 字段映射为 Java 枚举,能极大提升代码的可读性和健壮性。MyBatisPlus 提供了@EnumValue注解。

  1. 定义枚举类
// 文件路径:src/main/java/com/example/demo/enums/UserStatusEnum.java package com.example.demo.enums; import com.baomidou.mybatisplus.annotation.EnumValue; import lombok.Getter; @Getter public enum UserStatusEnum { DISABLED(0, "禁用"), ENABLED(1, "启用"); // @EnumValue 标记存储到数据库的值 @EnumValue private final Integer code; private final String desc; UserStatusEnum(Integer code, String desc) { this.code = code; this.desc = desc; } }
  1. 在实体类中使用枚举
// 在 User 实体类中添加字段 public class User { // ... 其他字段 private UserStatusEnum status; // 数据库对应字段可以是 `status` int类型 }
  1. 在配置中开启枚举处理(application.yml):
mybatis-plus: configuration: # 开启枚举类型处理 default-enum-type-handler: com.baomidou.mybatisplus.core.handlers.MybatisEnumTypeHandler

好处:存入数据库的是01,但在 Java 代码中你操作的是UserStatusEnum.ENABLED这样的对象,避免了魔法数字,也方便了状态判断和国际化。

7.2 字段自动加解密拦截器

对于密码、手机号、身份证号等敏感信息,我们希望在存入数据库时自动加密,查询时自动解密。这可以通过实现 MyBatis 的TypeHandler或使用拦截器完成。这里展示一个基于TypeHandler的简单 AES 加解密示例。

  1. 创建加解密工具类(生产环境请使用更安全的密钥管理方式):
// 文件路径:src/main/java/com/example/demo/handler/encrypt/AesEncryptor.java package com.example.demo.handler.encrypt; import org.springframework.util.Base64Utils; import javax.crypto.Cipher; import javax.crypto.spec.SecretKeySpec; import java.nio.charset.StandardCharsets; public class AesEncryptor { private static final String ALGORITHM = "AES/ECB/PKCS5Padding"; private static final byte[] KEY = "MySuperSecretKey16".getBytes(StandardCharsets.UTF_8); // 16字节密钥 public static String encrypt(String data) throws Exception { SecretKeySpec secretKey = new SecretKeySpec(KEY, "AES"); Cipher cipher = Cipher.getInstance(ALGORITHM); cipher.init(Cipher.ENCRYPT_MODE, secretKey); byte[] encryptedBytes = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8)); return Base64Utils.encodeToString(encryptedBytes); } public static String decrypt(String encryptedData) throws Exception { SecretKeySpec secretKey = new SecretKeySpec(KEY, "AES"); Cipher cipher = Cipher.getInstance(ALGORITHM); cipher.init(Cipher.DECRYPT_MODE, secretKey); byte[] decryptedBytes = cipher.doFinal(Base64Utils.decodeFromString(encryptedData)); return new String(decryptedBytes, StandardCharsets.UTF_8); } }
  1. 创建自定义 TypeHandler
// 文件路径:src/main/java/com/example/demo/handler/encrypt/EncryptTypeHandler.java package com.example.demo.handler.encrypt; import org.apache.ibatis.type.BaseTypeHandler; import org.apache.ibatis.type.JdbcType; import java.sql.CallableStatement; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; public class EncryptTypeHandler extends BaseTypeHandler<String> { @Override public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException { try { // 存入数据库前加密 ps.setString(i, AesEncryptor.encrypt(parameter)); } catch (Exception e) { throw new SQLException("加密字段失败", e); } } @Override public String getNullableResult(ResultSet rs, String columnName) throws SQLException { String encrypted = rs.getString(columnName); return decryptString(encrypted); } @Override public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException { String encrypted = rs.getString(columnIndex); return decryptString(encrypted); } @Override public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { String encrypted = cs.getString(columnIndex); return decryptString(encrypted); } private String decryptString(String encrypted) { if (encrypted == null) { return null; } try { return AesEncryptor.decrypt(encrypted); } catch (Exception e) { // 解密失败,可能该字段原本就不是加密数据,直接返回原值(根据业务调整) return encrypted; } } }
  1. 在实体类字段上应用 TypeHandler
// 在 User 实体类的 password 字段上添加注解 public class User { // ... @TableField(typeHandler = EncryptTypeHandler.class) private String password; // ... }

这样,当你调用userService.save(user)时,password字段在存入数据库前会自动加密。当通过userService.getById(1L)查询时,password字段会自动解密。注意:此方案仅对通过 MyBatisPlus 进行的操作生效。直接运行 SQL 或通过其他方式操作数据库则不会触发加解密。

8. 常见问题与排查思路

在整合过程中,你可能会遇到以下问题。这里提供一个快速排查指南。

问题现象可能原因排查方式解决方案
启动报错:java.lang.ClassNotFoundException: javax.servlet...MyBatisPlus 版本与 Spring Boot 3 不兼容,引用了javax包。检查pom.xmlmybatis-plus-boot-starter的版本。升级到3.5.3.1或更高版本。
启动报错:Failed to configure a DataSource未配置数据库连接,或配置有误。检查application.yml中的spring.datasource配置。1. 确认数据库服务已启动。
2. 检查URL、用户名、密码是否正确。
3. 添加spring.autoconfigure.exclude=...排除数据源自动配置(仅在不需DB时)。
Mapper 接口注入失败:NoSuchBeanDefinitionException@MapperScan注解未添加或扫描路径错误。1. 检查主启动类是否有@MapperScan
2. 检查路径是否包含所有 Mapper 接口。
在主启动类添加@MapperScan("你的.mapper包路径")
分页查询不生效,返回所有数据分页插件MybatisPlusInterceptor未配置。检查是否创建了配置类并添加了PaginationInnerInterceptor参照第6.2节创建MybatisPlusConfig配置类。
自动填充(如 createTime)不生效MetaObjectHandler未声明为@Component,或字段注解fill属性配置错误。1. 检查MyMetaObjectHandler类是否有@Component
2. 检查实体类字段的@TableField(fill = ...)注解。
确保处理器是 Spring Bean,且填充策略(INSERT/UPDATE)与操作匹配。
控制台不打印 SQL 日志未在配置中开启日志,或日志级别设置不正确。检查application.ymlmybatis-plus.configuration.log-impl配置。设置为org.apache.ibatis.logging.stdout.StdOutImpl。同时检查 Spring Boot 的logging.level.com.example.demo.mapper=DEBUG
使用LambdaQueryWrapper时报错:can’t find lambda cache可能是在非 Spring 管理的类(如普通的 Util 类)中使用了 Lambda 表达式。确认使用 Lambda 表达式的代码在 Spring Bean(如@Service,@Component)中。将相关逻辑移到 Spring 管理的 Bean 中,或改用QueryWrapper并手动写字段名字符串。
更新操作后,updateTime未自动更新MetaObjectHandlerupdateFill方法未正确实现,或更新时未使用 MyBatisPlus 的updateById等方法。1. 检查updateFill方法逻辑。
2. 确认更新操作调用的是userService.updateById(user)而非自己写UPDATESQL。
确保updateFill方法被调用,并使用 MyBatisPlus 的更新方法。

9. 生产环境最佳实践与建议

将 MyBatisPlus 用于生产环境,除了跑通功能,还需要关注稳定性、性能和可维护性。

  1. 版本管理:在pom.xml中使用<properties>统一管理关键依赖版本,特别是 MyBatisPlus 和 MyBatis 的版本,避免潜在的冲突。

    <properties> <mybatis-plus.version>3.5.7</mybatis-plus.version> <mybatis.version>3.5.16</mybatis.version> </properties> <dependencies> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>${mybatis-plus.version}</version> </dependency> </dependencies>
  2. 关闭开发环境日志:生产环境务必关闭log-impl: StdOutImpl,改为使用 SLF4J 并配置适当的日志级别,避免泄露敏感信息和影响性能。

    mybatis-plus: configuration: # 生产环境注释掉或删除此行 # log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  3. 复杂 SQL 使用 XML:对于多表关联、复杂统计等查询,不要强行用QueryWrapper拼接。应遵循 MyBatis 的传统,在 XML 文件中编写清晰、可维护的 SQL,并在 Mapper 接口中定义方法。

  4. 批量操作性能:MyBatisPlus 的Service层提供了saveBatchupdateBatchById等方法,但其默认实现可能不是真正的批量提交(例如,可能是循环单条插入)。对于大数据量批量操作,建议使用自定义的SqlSession批量模式,或评估使用ExecutorType.BATCH

  5. 逻辑删除的注意事项:一旦启用逻辑删除,所有delete操作都将变为update,所有select操作都会自动加上WHERE is_deleted=0。如果需要查询已删除的数据,可以使用@TableLogic注解的delvalvalue属性,或使用Wrapper手动覆盖条件。

  6. 监控与审计:考虑使用 MyBatisPlus 的SQL 注入分析插件(BlockAttackInnerInterceptor) 来防止全表更新/删除。对于关键数据变更,可以结合 Spring AOP 或 MyBatis 的插件机制实现操作日志审计。

  7. 代码生成器:对于大型项目,可以使用 MyBatisPlus 的代码生成器 (AutoGenerator)来快速生成 Entity、Mapper、Service、Controller 层代码。这能极大提升初期开发效率,但生成的代码可能需要根据项目规范进行二次调整。使用前请仔细阅读官方文档,配置好数据源、包路径和策略。

整合 JDK 17、Spring Boot 3 和 MyBatisPlus 是一个典型的“新版本栈”实践,其核心在于理解版本间的兼容性变化,并正确配置依赖和核心组件。从环境搭建、基础 CRUD、到条件构造器、分页、枚举映射、字段加解密,这套组合拳能覆盖绝大多数业务场景的开发需求。记住,遇到问题首先检查版本,其次是配置,最后才是代码逻辑。把本文中的配置和代码作为你的项目起点,根据实际业务进行裁剪和深化,你就能在 Spring Boot 3 的新生态中,继续享受 MyBatisPlus 带来的高效与便捷。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询