news 2026/10/14 23:28:34

MyBatis-Plus三大配置块详解:Configuration、GlobalConfig与DbConfig避坑指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
MyBatis-Plus三大配置块详解:Configuration、GlobalConfig与DbConfig避坑指南

1. 从一次线上事故说起:为什么配置项值得单独拎出来讲

去年帮一个朋友排查线上问题,现象很诡异:同一个查询接口,测试环境返回的createTime是正常的2024-03-15 10:23:45,到了生产环境却变成了2024-03-15T10:23:45,前端直接解析失败,页面上一片Invalid Date。查了半天代码,逻辑一模一样,最后定位到问题出在MyBatis-Plus的globalConfig里——两个环境的DbConfig配置不一致,一个开了JSR310时间类型适配,一个没开。

这件事让我意识到,很多人用 MyBatis-Plus 都是“能跑就行”,Configuration、GlobalConfig、DbConfig这三块配置基本靠复制粘贴,从来没认真看过每个字段到底管什么。等到出了玄学问题,才发现根子全在这几个配置类里。

这篇内容就是把这三大配置块彻底拆开讲清楚:Configuration管的是 MyBatis 原生那套核心行为,GlobalConfig是 MyBatis-Plus 自己加的全局策略,DbConfig则专门负责数据库层面的日志、主键、表前缀这些事。搞明白它们各自管什么、怎么配、配错了会怎样,你就能避开我踩过的那些坑。适合已经用过 MyBatis-Plus 但配置全靠抄的开发者,也适合想从 MyBatis 迁移过来、需要搞清楚配置差异的朋友。

2. Configuration 配置:MyBatis 原生能力的总开关

2.1 Configuration 到底是个什么东西

Configuration是 MyBatis 的核心配置类,你可以把它理解成整个 MyBatis 运行时的“大脑”。它持有MapperRegistry(Mapper 注册表)、TypeHandlerRegistry(类型处理器注册表)、MappedStatement集合(每条 SQL 的完整描述)、InterceptorChain(插件链)等等。MyBatis-Plus 并没有另起炉灶,而是在这个Configuration基础上做了增强,所以你在 MyBatis-Plus 里配的Configuration,本质上还是 MyBatis 那套东西。

在 Spring Boot 环境下,你通常不会直接 new 一个Configuration,而是通过MybatisPlusProperties里的configuration字段来配置,最终由MybatisPlusAutoConfiguration把它注入到SqlSessionFactoryBean里。理解这一点很关键:你配的每一项,最终都会反映到那个全局唯一的Configuration对象上。

2.2 最容易被忽略的 mapUnderscoreToCamelCase

这个配置项默认值是true(MyBatis-Plus 默认开启,原生 MyBatis 默认是false),作用是自动把数据库的user_name映射到 Java 的userName。看起来很方便,但它有个坑:一旦你手动写了resultMap,这个自动映射就会失效,因为resultMap是显式映射,优先级高于自动映射。

我见过有同学在实体类上加了@TableField("user_name"),又在 XML 里写了resultMap,结果字段死活映射不上,查了半天才发现是两套映射规则打架。我的建议是:要么全用注解 + 自动映射,要么全用resultMap显式映射,别混着来。

mybatis-plus: configuration: map-underscore-to-camel-case: true

2.3 cacheEnabled 与二级缓存的取舍

cacheEnabled默认true,控制的是二级缓存的开关。注意,它只是“总开关”,真正要用二级缓存还得在 Mapper XML 里加<cache/>标签。很多人以为开了这个就能缓存,结果发现每次还是查库,就是因为没加<cache/>。

但我要泼盆冷水:在分布式环境下,MyBatis 的二级缓存基本是个坑。它是基于PerpetualCache的本地缓存,多节点部署时各节点缓存不一致,更新操作容易读到脏数据。我个人的做法是直接关掉,缓存交给 Redis 这类外部组件统一管理,职责更清晰。

mybatis-plus: configuration: cache-enabled: false

2.4 logImpl 与日志实现的绑定

logImpl指定 MyBatis 用哪个日志框架输出 SQL,可选值有SLF4J、LOG4J、LOG4J2、JDK_LOGGING、COMMONS_LOGGING、STDOUT_LOGGING、NO_LOGGING。如果你不配,MyBatis 会按固定顺序自动查找,找到哪个用哪个。

这里有个实操经验:如果你用的是 Spring Boot,默认日志是 Logback,对应 SLF4J,所以显式配成SLF4J最稳妥。我遇到过项目里同时引入了 Log4j 和 Logback,MyBatis 自动选了 Log4j,结果 SQL 日志跑到另一个文件里去了,排查起来很费劲。

mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.slf4j.Slf4jImpl

2.5 其他值得关注的配置项

defaultStatementTimeout设置 SQL 超时时间(秒),生产环境强烈建议配上,防止慢查询拖垮连接池。defaultExecutorType默认是SIMPLE,如果你有大量批量操作,可以改成BATCH,但要注意BATCH模式下查询结果可能不是你预期的(因为批处理会延迟执行)。callSettersOnNulls默认false,意味着查询结果为 null 的字段不会调用 setter,如果你用 Map 接收结果,null 字段会直接不出现,需要它出现就设为true。

这些配置项看着零散,但每一个背后都对应着一类真实场景。我的建议是:不要一次性全配上,用到哪个查哪个,配完写注释说明为什么配,否则半年后你自己都不记得当初为啥要改。

3. GlobalConfig 全局配置:MyBatis-Plus 的策略中枢

3.1 GlobalConfig 与 Configuration 的分工

如果说Configuration是 MyBatis 的大脑,那GlobalConfig就是 MyBatis-Plus 加装的“策略中心”。它管的是那些跨所有 Mapper 生效的全局行为:主键生成策略、字段自动填充、逻辑删除、SQL 注入器等等。这些能力原生 MyBatis 没有,是 MyBatis-Plus 的增值部分。

在 Spring Boot 里,GlobalConfig通过mybatis-plus.global-config前缀配置。它和Configuration是并列关系,各管各的,互不干扰。理解这个分工,你就不会把db-config的配置写到configuration下面去了——这是新手最常犯的错。

3.2 dbConfig 主键策略:ASSIGN_ID 还是 AUTO

dbConfig.idType是全局主键策略,默认是ASSIGN_ID(雪花算法)。这个默认值在分布式环境下很香,因为生成的 ID 全局唯一且趋势递增。但如果你用的是 MySQL 自增主键,就必须改成AUTO,否则插入时会用雪花 ID 覆盖掉自增,导致主键混乱。

mybatis-plus: global-config: db-config: id-type: auto

这里有个判断标准:单库单表用AUTO,分库分表或需要提前生成 ID 用ASSIGN_ID。我见过有项目分库分表了还用AUTO,结果每个分片都从 1 开始自增,ID 直接冲突,数据全乱套。

3.3 logicDeleteField 逻辑删除的完整配置

逻辑删除是 MyBatis-Plus 的招牌功能之一,但配置不完整会导致查询把已删除数据也带出来。完整配置需要三部分:全局指定逻辑删除字段名、删除值、未删除值。

mybatis-plus: global-config: db-config: logic-delete-field: deleted logic-delete-value: 1 logic-not-delete-value: 0

配完之后,deleteById会自动变成UPDATE ... SET deleted=1,所有查询自动追加WHERE deleted=0。但要注意:手写的 XML SQL 不会自动追加这个条件,你得自己加。这是很多人踩的坑,以为配了全局就万事大吉,结果自定义 SQL 把删除数据查出来了。

3.4 字段自动填充的配置与实现

自动填充createTime、updateTime这类字段,能省掉大量重复代码。配置分两步:先在GlobalConfig里不用配(它靠MetaObjectHandler实现),然后在实体类字段上加@TableField(fill = FieldFill.INSERT)注解,最后实现MetaObjectHandler接口。

@Component public class MyMetaObjectHandler implements MetaObjectHandler { @Override public void insertFill(MetaObject metaObject) { this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now()); this.strictInsertFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now()); } @Override public void updateFill(MetaObject metaObject) { this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now()); } }

实操心得:strictInsertFill只在字段为 null 时填充,如果你手动设了值,它不会覆盖。这个特性很有用,比如数据迁移时想保留原始创建时间,手动设值即可。另外,updateFill在updateById时会触发,但update(entity, wrapper)这种批量更新不一定触发,需要实测确认。

3.5 banner 与 SQL 注入器的开关

global-config.banner默认true,启动时会打印 MyBatis-Plus 的 ASCII 图案。生产环境建议关掉,日志干净些。sqlInjector一般不用动,除非你要自定义通用方法。DbConfig里的tablePrefix可以给所有表统一加前缀,比如t_,适合多模块共库时做隔离。

4. DbConfig 日志配置:让 SQL 无处遁形

4.1 日志配置的三种姿势

MyBatis-Plus 的 SQL 日志配置,本质上还是走 MyBatis 那套logImpl,但实际项目里有三种常见做法,各有适用场景。

第一种是全局log-impl配成StdOutImpl,SQL 直接打到控制台。开发阶段最省事,但生产环境千万别用,日志量爆炸且无法分级。

mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

第二种是配成Slf4jImpl,然后通过 Logback 的 logger 级别控制。这是生产环境的标准做法,可以精确到某个 Mapper 包。

mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.slf4j.Slf4jImpl logging: level: com.example.mapper: debug

第三种是用 MyBatis-Plus 的p6spy或PerformanceInterceptor(新版已移除,改用p6spy)做 SQL 性能分析。这个适合排查慢查询,能打印执行时间和完整 SQL。

4.2 日志级别与包路径的精确控制

很多人配了logging.level.com.example.mapper: debug却发现 SQL 没打出来,原因通常是 Mapper 接口不在这个包下,或者用的是 XML 而 XML 的 namespace 和接口包路径不一致。MyBatis 的日志 logger 名是 Mapper 接口的全限定名,所以你的包路径必须精确匹配到接口所在包。

我的做法是:先配到debug级别,确认 SQL 出来了,再根据实际需要收窄到具体 Mapper。别一上来就配com.example: debug,那样整个项目的日志都会被刷屏。

4.3 生产环境日志配置的取舍

生产环境我一般这么配:log-impl用Slf4jImpl,Mapper 包级别设为info,只在排查问题时临时调到debug。同时开启慢 SQL 日志,通过p6spy或数据库自身的慢查询日志来捕获。

mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.slf4j.Slf4jImpl logging: level: com.example.mapper: info

这里有个经验:SQL 日志里带参数值会暴露敏感信息,比如手机号、身份证。生产环境要么不打参数,要么做脱敏。MyBatis 默认打的是Preparing: SELECT ... WHERE phone = ?加Parameters: 138xxxx(String),参数是明文,需要额外处理。

4.4 日志配置常见问题速查表

现象可能原因解决方向
SQL 完全不打印log-impl 未配或配错检查是否配了 Slf4jImpl 或 StdOutImpl
只打印 Preparing 不打印 Parameters日志级别不够调到 debug 级别
日志重复打印两次引入了多个日志实现排除多余的日志依赖
生产环境日志文件暴涨用了 StdOutImpl 或级别过低改 Slf4jImpl + info 级别
参数显示为 nullcallSettersOnNulls 未开设为 true 或检查参数传递

5. 三大配置块的协作关系与实操避坑

5.1 配置加载顺序与优先级

这三块配置的加载顺序是:先Configuration(MyBatis 原生),再GlobalConfig(MyBatis-Plus 全局),最后DbConfig(数据库策略)。它们之间没有覆盖关系,各管各的。但有一个交叉点:主键策略。GlobalConfig.dbConfig.idType是全局默认,实体类上的@TableId(type = IdType.AUTO)是局部覆盖,局部优先级高于全局。

这个优先级规则很重要。我见过有人在全局配了ASSIGN_ID,某个表想用自增,就在实体类上加了@TableId(type = IdType.AUTO),结果发现还是雪花 ID。排查半天才发现是@TableId没加value属性,或者注解加错了位置。记住:局部永远覆盖全局,但前提是局部配置生效了。

5.2 一个完整的配置示例

把三块配置整合到一个application.yml里,方便你直接抄作业:

mybatis-plus: configuration: map-underscore-to-camel-case: true cache-enabled: false log-impl: org.apache.ibatis.logging.slf4j.Slf4jImpl default-statement-timeout: 30 global-config: banner: false db-config: id-type: auto logic-delete-field: deleted logic-delete-value: 1 logic-not-delete-value: 0 table-prefix: t_ logging: level: com.example.mapper: debug

这份配置覆盖了 90% 的日常场景。table-prefix按需加,不需要就删掉。default-statement-timeout设 30 秒,防止慢查询。

5.3 配置不生效的排查思路

配置不生效,八成是这几个原因:配置前缀写错(比如把db-config写成dbConfig,YAML 里要用中划线)、配置类没被扫描到(自定义GlobalConfigBean 时忘了@Bean)、多数据源场景下配置没绑定到正确的 SqlSessionFactory。

排查方法很简单:启动时打个断点,看MybatisPlusProperties里的字段有没有值。或者开debug日志,看MybatisPlusAutoConfiguration的日志输出。我一般会在启动类里加一行log.info("MP配置: {}", mybatisPlusProperties),一目了然。

5.4 多数据源下的配置隔离

多数据源是配置问题的高发区。每个数据源需要独立的SqlSessionFactory,也就需要独立的Configuration和GlobalConfig。如果你用@ConfigurationProperties绑定,记得给每个数据源配不同的前缀。

@Bean @ConfigurationProperties("mybatis-plus.datasource1") public MybatisPlusProperties props1() { return new MybatisPlusProperties(); }

实操心得:多数据源下,GlobalConfig的dbConfig是共享的,因为它是全局单例。如果两个数据源的主键策略不同,就得在实体类上用@TableId局部覆盖,没法在全局层面区分。这是 MyBatis-Plus 的一个设计限制,用之前要有心理准备。

6. 几个真实踩坑案例的复盘

6.1 时间类型映射错乱

回到开头那个案例。LocalDateTime在 MyBatis 里需要JSR310TypeHandler支持,MyBatis 3.4.5+ 内置了,但前提是Configuration里注册了对应的 TypeHandler。MyBatis-Plus 默认会注册,但如果你的项目里手动覆盖了TypeHandlerRegistry,可能就把默认的冲掉了。

解决方法是显式确认:configuration.default-enum-type-handler和 JSR310 相关的 handler 是否在。或者更简单,在实体类字段上加@TableField(typeHandler = LocalDateTimeTypeHandler.class)强制指定。

6.2 逻辑删除与唯一索引冲突

逻辑删除有个经典问题:表上有个唯一索引uk_username,删除用户 A 后,再注册同名用户会报唯一键冲突,因为已删除的记录还在表里。解决方案有两种:一是把唯一索引改成(username, deleted)联合索引,二是删除时把 username 改成username_deleted_时间戳。我倾向第二种,改动小且不影响查询。

6.3 自动填充在批量插入时失效

MetaObjectHandler的insertFill在saveBatch时是生效的,但在自定义的insertBatchSomeColumn里可能不生效,因为后者走的是自定义 SQL 注入器。如果遇到批量插入时间字段为空,检查一下是不是用了自定义注入器,是的话需要在 SQL 里手动加填充逻辑。

7. 配置管理的个人经验谈

配了这么多年 MyBatis-Plus,我最大的体会是:配置项不是越多越好,而是越明确越好。每个配置项都应该有存在的理由,要么解决了一个具体问题,要么规避了一类风险。那些“别人配了我也配”的项,往往就是日后出问题的隐患。

另外,配置一定要和代码一起进版本控制,并且写清楚注释。我见过太多项目,application.yml里一堆配置没有任何说明,换个人接手根本不敢动。我的做法是在每个非默认配置上方加一行注释,说明为什么这么配、不这么配会怎样。这个习惯帮我省了无数次排查时间。

最后一个建议:新项目初始化时,先把这三块配置按最小可用原则配好,跑通一个增删改查,再逐步加功能。别一上来就把所有高级特性都打开,出了问题你都不知道是哪个配置引起的。配置这东西,跟做菜一样,盐要一点点加,一次加到位容易齁着。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/14 23:26:02

从单体到集群:任务调度系统拆解分布式架构核心痛点

分布式系统这个概念&#xff0c;很多人刚接触时会觉得特别虚。可能你读过一堆关于节点、副本、一致性协议的材料&#xff0c;听过 CAP 定理、共识算法这些名词&#xff0c;但关上文档还是说不清楚它到底解决了什么问题&#xff0c;以及为什么会让系统变复杂。我自己前些年也是这…

作者头像 李华
网站建设 2026/10/14 23:24:33

FlinkX 异构数据同步实战:插件化架构与批流统一解析

1. 为什么数据同步这件事值得单独拎出来聊做数据平台的人都有一个共识&#xff1a;数据同步看起来简单&#xff0c;做起来要命。尤其是当业务系统越来越多、数据源越来越杂、实时性要求越来越高的时候&#xff0c;你会发现“把数据从A搬到B”这句话背后藏着无数坑。FlinkX 就是…

作者头像 李华
网站建设 2026/10/14 23:24:29

本地大模型写代码:分层架构与可调试编程助手实战

1. 项目概述&#xff1a;本地大模型不是“装个软件就写代码”&#xff0c;而是构建一个可掌控、可调试、可迭代的智能编程助手“本地大模型&#xff0c;怎么写代码”——这八个字最近在技术社区刷屏&#xff0c;但很多人点进去才发现&#xff0c;内容要么是教你怎么用Ollama拉一…

作者头像 李华
网站建设 2026/10/14 23:23:15

本地AI求职框架:精准匹配与隐私保护实战

1. 为什么“AI求职”这件事需要一套本地框架1.1 从“海投”到“精投”的转变逻辑这两年AI工具普及之后&#xff0c;求职这件事的画风变了不少。以前是一个人对着招聘网站手动翻页、复制粘贴、改简历&#xff0c;一天能投出去二三十份就算勤快了。现在有了各种自动化脚本和AI辅助…

作者头像 李华
网站建设 2026/10/14 23:22:20

本地AI绘图全家桶搭建指南:从硬件评估到工作流管理

最近总有朋友问我&#xff1a;想在本地电脑上搭一套“本地AI绘图全家桶”&#xff0c;到底该装哪些东西&#xff0c;怎么搭配才够用&#xff1f;我最初以为这就是装一个画图工具的事&#xff0c;真把整套环境跑起来之后才明白&#xff0c;一个能稳定出图、能改图、能精细化控制…

作者头像 李华
网站建设 2026/10/14 23:22:16

Unity编辑器扩展:资源批量处理实战指南

1. 项目概述&#xff1a;为什么批量处理资源是Unity开发中绕不开的“体力活”在Unity项目做到中后期&#xff0c;资源数量动辄上千——贴图、模型、音频、预制体、脚本、动画片段……光靠手动右键→Inspector里改一个参数&#xff0c;再点Apply&#xff0c;重复一百次&#xff…

作者头像 李华