MyBatis 3.5 源码手记:执行器、动态 SQL 与缓存边界
MyBatis 3.5 源码手记:执行器、动态 SQL 与缓存边界
基线:MyBatis 3.5.x、Spring Boot 3、Java 17+。
1. SqlSession 到 JDBC
典型调用链是:
SqlSession -> Executor -> StatementHandler -> JDBC Statement
-> ResultSetHandler
SqlSession 是门面,Executor 负责 SQL 执行、事务和缓存。MappedStatement 描述映射后的 SQL,StatementHandler 负责参数设置与执行,ResultSetHandler 负责结果对象构造。
2. 动态 SQL 和参数
XML 动态节点最终组合成 SqlSource。#{} 会生成参数映射并使用 PreparedStatement;${} 是字符串替换,只能用于白名单化表名、列名和排序字段。
OGNL 负责部分动态表达式求值,但表达式能力不等于安全边界。不要让不可信输入控制表达式或 SQL 结构。
3. Executor
SimpleExecutor 每次创建 Statement;ReuseExecutor 复用 Statement;BatchExecutor 延迟批量更新;CachingExecutor 装饰其他 Executor,提供 namespace 二级缓存。
选择 Executor 需要结合事务、失败重试、内存和 JDBC 驱动。BatchExecutor 不是简单打开开关就一定更快。
4. 一级和二级缓存
一级缓存通常位于 SqlSession/Executor 生命周期内,长时间复用可能读到旧数据。二级缓存位于 namespace,涉及序列化、事务提交和失效一致性。跨实例强一致场景不应默认启用二级缓存。
5. 源码阅读方法
先跟 Mapper 代理,再跟 MappedStatement 注册、Executor 装饰链、ParameterMapping、TypeHandler 和 ResultMap。升级时以实际锁定版本源码为准,不要把内部字段当作稳定 API。