告别繁琐SQL!Spring Boot 3.2 + MybatisPlus 3.5.x 配置与常用注解避坑指南

张开发
2026/4/20 10:53:40 15 分钟阅读

分享文章

告别繁琐SQL!Spring Boot 3.2 + MybatisPlus 3.5.x 配置与常用注解避坑指南
Spring Boot 3.2 MyBatis-Plus 3.5.x 实战避坑手册从配置陷阱到注解玄学当你在深夜调试MyBatis-Plus时是否经历过这样的绝望瞬间——明明按照教程一步步操作启动时却报出Invalid bound statement或是发现TableField注解像被施了隐身咒般毫无反应本文将带你直击这些灵异现象背后的真相用外科手术式精准拆解配置与注解的每个技术细节。1. 那些年我们踩过的配置坑1.1 配置文件YAML的温柔陷阱在Spring Boot 3.2中application.yml的缩进就像Python的缩进一样致命。来看个典型错误示例mybatis-plus: mapper-locations: classpath*:/mapper/**/*.xml type-aliases-package: com.example.entity # 这里缩进错误这个配置会导致TypeAliases扫描完全失效。正确的姿势应该是mybatis-plus: mapper-locations: classpath*:/mapper/**/*.xml type-aliases-package: com.example.entity # 保持同级缩进关键配置项对照表配置项默认值典型错误正确示例mapper-locations无classpath:/mapper/*.xmlclasspath*:/mapper/**/*.xmltype-handlers-package无com.example.handlercom.example.typehandlerconfiguration.map-underscore-to-camel-casefalsetrue(3.4.x旧版)true(3.5.x需要额外配置)提示在MyBatis-Plus 3.5.x中开启驼峰映射需要额外添加mybatis-plus: configuration: map-underscore-to-camel-case: true1.2 多数据源下的死亡缠绕当项目需要连接多个数据库时常见的连环坑包括Primary注解遗漏Configuration public class DataSourceConfig { Bean Primary // 这个注解绝对不能少 public DataSource firstDataSource() {...} Bean public DataSource secondDataSource() {...} }Mapper扫描范围重叠MapperScan(basePackages com.dao.mysql, sqlSessionTemplateRef mysqlTemplate) public class MysqlConfig {} MapperScan(basePackages com.dao.postgres, sqlSessionTemplateRef postgresTemplate) public class PostgresConfig {}如果两个包路径存在包含关系就会引发BeanDefinitionOverrideException。建议采用严格的包名隔离com.dao.mysql com.dao.postgresql2. 注解背后的黑暗魔法2.1 TableName你以为的简单其实不简单这个看似简单的注解藏着三个致命陷阱场景一表名前缀统一配置TableName(user) // 当全局配置了表前缀时实际表名会是t_user public class User {}解决方案TableName(value user, keepGlobalPrefix false) // 显式禁用全局前缀场景二动态表名切换public class User { TableField(exist false) private String tableSuffix; public String getDynamicTableName() { return user_ tableSuffix; } }需要在配置类中注册动态表名处理器public class MybatisPlusConfig { Bean public DynamicTableNameParser dynamicTableNameParser() { return (sql, metaObject) - { Object tableSuffix metaObject.getValue(tableSuffix); return tableSuffix ! null ? user_ tableSuffix : user; }; } }2.2 TableId主键类型的修罗场主键类型配置错误会导致各种诡异问题// 雪花ID配置MySQL的BIGINT TableId(type IdType.ASSIGN_ID) private Long id; // 自增主键需要数据库设置AUTO_INCREMENT TableId(type IdType.AUTO) private Integer id; // 全局ID生成器需实现IdentifierGenerator接口 TableId(type IdType.ASSIGN_UUID) private String id;常见踩坑点数据库字段是BIGINT但实体类用Integer忘记在application.yml配置id-type: ASSIGN_ID混用AUTO和ASSIGN_ID策略2.3 TableField映射的七十二变这个注解的复杂程度远超想象Case 1字段填充策略TableField(fill FieldFill.INSERT) private LocalDateTime createTime; TableField(fill FieldFill.INSERT_UPDATE) private LocalDateTime updateTime;需要实现元对象处理器Component public class MyMetaObjectHandler implements MetaObjectHandler { Override public void insertFill(MetaObject metaObject) { this.strictInsertFill(metaObject, createTime, LocalDateTime.class, LocalDateTime.now()); } Override public void updateFill(MetaObject metaObject) { this.strictUpdateFill(metaObject, updateTime, LocalDateTime.class, LocalDateTime.now()); } }Case 2非表字段的三种处理方式// 方式1静态忽略 TableField(exist false) private String tempValue; // 方式2动态忽略通过Wrapper queryWrapper.select(Student.class, info - !info.getColumn().equals(temp_value)); // 方式3条件判断 TableField(condition SqlCondition.LIKE) private String name;3. 高阶玩家的性能调优3.1 SQL注入器自定义魔法实现一个逻辑删除增强器public class MyLogicSqlInjector extends DefaultSqlInjector { Override public ListAbstractMethod getMethodList(Class? mapperClass) { ListAbstractMethod methodList super.getMethodList(mapperClass); methodList.add(new DeleteAll()); // 添加自定义方法 return methodList; } } public class DeleteAll extends AbstractMethod { Override public MappedStatement injectMappedStatement(...) { String sql delete from tableInfo.getTableName(); SqlSource sqlSource languageDriver.createSqlSource(...); return this.addDeleteMappedStatement(mapperClass, deleteAll, sqlSource); } }注册到Spring容器Bean public MyLogicSqlInjector myLogicSqlInjector() { return new MyLogicSqlInjector(); }3.2 分页插件性能优化默认分页在百万级数据时会出现性能问题Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor new MybatisPlusInterceptor(); // 优化版分页插件 PaginationInnerInterceptor paginationInterceptor new PaginationInnerInterceptor(DbType.MYSQL); paginationInterceptor.setOptimizeJoin(true); // 优化联表查询 paginationInterceptor.setMaxLimit(1000L); // 单页最大1000条 interceptor.addInnerInterceptor(paginationInterceptor); return interceptor; }性能对比数据数据量传统分页(ms)优化分页(ms)10万120045050万58002100100万超时42004. 调试技巧从灵异到科学4.1 日志配置的黄金组合在application.yml中添加logging: level: com.baomidou.mybatisplus: DEBUG org.springframework.jdbc.datasource: TRACE配合MyBatis-Plus原生日志mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl4.2 元数据检查工具在测试类中添加诊断方法Test void showMetaData() { TableInfoHelper.getTableInfos().forEach(tableInfo - { System.out.println( Table: tableInfo.getTableName() ); tableInfo.getFieldList().forEach(field - { System.out.println(field.getProperty() - field.getColumn()); }); }); }输出示例 Table: user id - user_id name - user_name createTime - create_time4.3 异常速查手册异常信息可能原因解决方案Invalid bound statementmapper.xml路径错误检查mapper-locations配置Unknown column xxx in field list字段映射失败检查TableField或开启map-underscore-to-camel-caseCould not set parameters类型不匹配检查实体类与数据库字段类型Table database.table doesnt exist表名前缀问题检查TableName的keepGlobalPrefix

更多文章