1. 面试场景还原与技术痛点分析
那天下午的面试场景至今记忆犹新——当面试官连续抛出十几个MyBatis深度问题时,我才意识到平时停留在CRUD层面的使用是多么肤浅。从动态SQL的底层实现到一级缓存引发的数据一致性问题,每个问题都直指框架设计的核心思想。这种"吊打式"面试恰恰暴露了大多数开发者对MyBatis的三大认知误区:
- 配置驱动型思维:满足于XML配置和基础注解,忽视框架的运行时行为
- 黑箱式使用:只关注SQL执行结果,不探究StatementHandler等核心组件的工作机制
- 场景化知识缺失:对分库分表、多数据源等企业级场景的整合方案缺乏实践
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. MyBatis核心机制深度解析
2.1 会话管理机制与缓存陷阱
SqlSession的线程安全问题常被忽视。实测发现,当使用Spring集成时,SqlSessionTemplate通过动态代理将每个方法调用映射到独立的SqlSession。这种设计带来一个关键特性:
java复制// 伪代码展示Spring管理的SqlSession生命周期
public class SqlSessionTemplate {
public <T> T execute(SqlSessionCallback<T> action) {
SqlSession session = sessionFactory.openSession();
try {
return action.doInSession(session); // 方法级会话
} finally {
session.close();
}
}
}
一级缓存的失效场景需要特别注意:
- 执行UPDATE/DELETE操作后,对应Namespace的缓存立即清除
- 手动调用clearCache()方法时
- 设置flushCache="true"的查询语句会跳过缓存检查
踩坑记录:在批量插入场景中,如果不及时调用sqlSession.clearCache(),可能导致后续查询读取到脏数据
2.2 动态SQL的编译时优化
面试中最让我措手不及的问题是:"#{}和${}在预编译阶段有何本质区别?" 实际上,MyBatis在解析SQL时会构建抽象语法树:
- #{}参数:生成PreparedStatement参数占位符(?)
- ${}参数:直接文本替换,存在SQL注入风险
动态SQL的解析过程可以通过OGNL表达式调试:
xml复制<select id="findUsers">
SELECT * FROM users
<where>
<if test="@org.apache.ibatis.ognl.Ognl@isNotEmpty(name)">
AND name LIKE #{name}
</if>
</where>
</select>
2.3 插件开发与执行链路
自定义插件需要理解四大核心接口:
- Executor (update, query, flushStatements)
- StatementHandler (prepare, parameterize)
- ParameterHandler (get/set parameters)
- ResultSetHandler (handleResultSets)
实现分页插件的典型示例:
java复制@Intercepts({
@Signature(type= Executor.class,
method="query",
args={MappedStatement.class,Object.class,
RowBounds.class,ResultHandler.class})
})
public class PaginationPlugin implements Interceptor {
// 拦截逻辑实现
}
3. 企业级应用场景实战
3.1 多数据源动态路由
在金融系统中,我们经常需要根据业务编码路由到不同数据库。通过AbstractRoutingDataSource实现:
java复制public class BizRoutingDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return BizContextHolder.getBizCode(); // 线程上下文获取业务标识
}
}
配置要点:
- 每个数据源需要独立配置TransactionManager
- MyBatis映射器接口需按数据源分包存放
- 事务注解需明确指定事务管理器:@Transactional("orderTxManager")
3.2 批量操作性能优化
对比三种批量插入方案的性能(测试数据量10万条):
| 方案 | 耗时(ms) | 内存消耗(MB) |
|---|---|---|
| 循环单条插入 | 28500 | 120 |
| BatchExecutor | 3200 | 85 |
| 批量模式+rewriteBatchedStatements | 1800 | 65 |
最佳实践代码示例:
java复制@Options(useGeneratedKeys=true, keyProperty="id")
@Insert("<script>INSERT INTO users (name,age) VALUES " +
"<foreach collection='list' item='item
