跳转到内容

Mapper 与 SQL 注入

MyBatis-Plus 的 CRUD 不是运行时拼接一段 SQL 字符串,而是在 Mapper 解析阶段生成并注册 MappedStatement。

先给答案:MyBatis-Plus 的 CRUD 不是运行时拼接一段 SQL 字符串,而是在 Mapper 解析阶段…

Section titled “先给答案:MyBatis-Plus 的 CRUD 不是运行时拼接一段 SQL 字符串,而是在 Mapper 解析阶段…”

MyBatis-Plus 的 CRUD 不是运行时拼接一段 SQL 字符串,而是在 Mapper 解析阶段生成并注册 MappedStatement。 理解Mapper 与 SQL 注入时,要先确认入口与状态归属,再跟踪控制流或数据流的推进顺序,最后落到对外可观察的结果。

主要失效边界集中在“自定义 XML 同名、自定义 injector 漏方法、SQL 片段参数不一致”这些场景。它们破坏的是容量、顺序、并发或生命周期前提;排查时应先确认状态是否仍由正确对象持有,再核对推进条件和清理路径。

主要失效边界集中在“自定义 XML 同名、自定义 injector 漏方法、SQL 片段参数不一致”这些场景。它们破坏的是容量、顺序、并发或生命周期前提;排查时应先确认状态是否仍由正确对象持有,再核对推进条件和清理路径。

Mapper interface
└─► SqlInjector#getMethodList
└─► AbstractMethod#inject
├─► build SQL / SqlSource
├─► build ResultMap
└─► Configuration.addMappedStatement

ISqlInjector 定义方法列表,AbstractMethod 提供通用注入模板,具体方法类只负责 SQL 形态和参数映射:见 ISqlInjector.java:26-50、DefaultSqlInjector.java:30-80、AbstractMethod.java:53-120、AbstractMethod.java:150-210、AbstractMethod.java:250-300、AbstractMethod.java:390-445。

BaseMapper 的方法名与注入的 statement id 对齐,代理调用时直接进入 MyBatis 的 MappedStatement;批量方法和扩展方法可以通过自定义 injector 增加:见 BaseMapper.java:97-150、BaseMapper.java:480-570、DefaultSqlInjector.java:80-120、MybatisMapperAnnotationBuilder.java:68-150。

替代方案:每次调用 insert/updateById 时动态生成 SQL。 为什么不行:SQL、参数映射和 ResultMap 都会重复构造,也难以与 MyBatis 的缓存和 statement 生命周期一致。 证据:AbstractMethod#inject 通过 addMappedStatement 把结果注册到 Configuration,运行时只做参数绑定和执行。

场景 现象 原因 规避
自定义 XML 同名 默认方法未注入 注入器检测到 statement 已存在 修改 statement id 或复用 XML
自定义 injector 漏方法 BaseMapper API 报错 方法列表没有完整覆盖 基于默认列表扩展
SQL 片段参数不一致 BindingException script 与 parameterType 不匹配 对照 TableInfo 和参数映射

代码生成不一定意味着生成 Java 文件;把通用操作编译成运行时元对象,同样能获得复用性并避免源码膨胀。

面试锚点

  • 通用 CRUD 的 MappedStatement 在何时生成?
  • AbstractMethod 的模板职责是什么?
  • XML 与注入方法同名时谁生效?