你是否曾好奇:当你调用MyBatis的selectOne()方法时,你的SQL语句究竟经历了怎样的旅程才最终到达数据库?本文将深入MyBatis内核,揭示从SqlSession到JDBC的完整执行链路,让你彻底掌握MyBatis的核心工作原理。
一、执行链路全景图
在深入源码前,先看整体执行流程:
SqlSession -> Executor -> StatementHandler -> ParameterHandler -> JDBC Statement -> ResultSetHandler
二、SqlSession:入口门户
SqlSession是MyBatis的核心接口,所有数据库操作都从这里开始。以DefaultSqlSession为例:
// DefaultSqlSession.java
public <E> List<E> selectList(String statement, Object parameter) {
MappedStatement ms = configuration.getMappedStatement(statement);
return executor.query(ms, parameter, RowBounds.DEFAULT, Executor.NO_RESULT_HANDLER);
}
关键点:
- 通过statement从Configuration获取MappedStatement
- 委托给Executor执行查询
三、Executor:执行引擎
Executor是真正的执行者,采用典型的命令模式。以SimpleExecutor为例:
// SimpleExecutor.java
public <E> List<E> query(MappedStatement ms, Object parameter,
RowBounds rowBounds, ResultHandler resultHandler) {
BoundSql boundSql = ms.getBoundSql(parameter);
CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql);
return query(ms, parameter, rowBounds, resultHandler, key, boundSql);
}
执行过程:
- 获取BoundSql(包含最终要执行的SQL和参数映射)
- 创建缓存Key(如果启用二级缓存)
- 执行doQuery()方法
四、StatementHandler:SQL语句处理器
Executor最终会调用StatementHandler:
// SimpleExecutor.doQuery()
StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter,
rowBounds, resultHandler, boundSql);
stmt = prepareStatement(handler, ms.getStatementLog());
return handler.query(stmt, resultHandler);
PreparedStatementHandler核心处理流程:
// SimpleExecutor.doQuery()
StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter,
rowBounds, resultHandler, boundSql);
stmt = prepareStatement(handler, ms.getStatementLog());
return handler.query(stmt, resultHandler);
PreparedStatementHandler核心处理流程:
// PreparedStatementHandler.java
public <E> List<E> query(Statement statement, ResultHandler resultHandler) {
PreparedStatement ps = (PreparedStatement) statement;
ps.execute();
return resultSetHandler.handleResultSets(ps);
}
五、ParameterHandler:参数处理专家
参数处理发生在StatementHandler初始化时:
// DefaultParameterHandler.java
public void setParameters(PreparedStatement ps) {
for (int i = 0; i < parameterMappings.size(); i++) {
ParameterMapping parameterMapping = parameterMappings.get(i);
Object value;
// 复杂参数处理逻辑...
TypeHandler typeHandler = parameterMapping.getTypeHandler();
typeHandler.setParameter(ps, i + 1, value, parameterMapping.getJdbcType());
}
}
六、JDBC交互:最后的桥梁
MyBatis最终通过标准的JDBC API与数据库交互:
// PreparedStatementHandler.execute()
public int update(Statement statement) throws SQLException {
PreparedStatement ps = (PreparedStatement) statement;
ps.execute();
return ps.getUpdateCount();
}
七、ResultSetHandler:结果集转换大师
结果集处理是最复杂的部分:
// DefaultResultSetHandler.java
public List<Object> handleResultSets(Statement stmt) throws SQLException {
final List<Object> multipleResults = new ArrayList<>();
ResultSet rs = stmt.getResultSet();
while (rs != null) {
// 处理单结果集
Object result = getSingleResult(rs);
multipleResults.add(result);
// 处理多结果集
if (stmt.getMoreResults()) {
rs = stmt.getResultSet();
} else {
rs = null;
}
}
return collapseSingleResultList(multipleResults);
}
八、设计模式应用
MyBatis执行链路中巧妙运用了多种设计模式:
- 门面模式:SqlSession作为统一入口
- 责任链模式:插件拦截器实现
- 模板方法模式:BaseExecutor定义执行骨架
- 装饰器模式:CachingExecutor包装普通Executor
九、性能优化关键点
- Statement重用:ReuseExecutor会缓存PreparedStatement
- 批量处理:BatchExecutor优化批量操作
- 延迟加载:通过Proxy实现关联对象的延迟加载
- 缓存机制:一级缓存(Session级别)和二级缓存(Mapper级别)
十、插件扩展原理
MyBatis通过动态代理实现插件机制:
// Plugin.java
public static Object wrap(Object target, Interceptor interceptor) {
Map<Class<?>, Set<Method>> signatureMap = getSignatureMap(interceptor);
Class<?> type = target.getClass();
Class<?>[] interfaces = getAllInterfaces(type, signatureMap);
if (interfaces.length > 0) {
return Proxy.newProxyInstance(
type.getClassLoader(),
interfaces,
new Plugin(target, interceptor, signatureMap));
}
return target;
}
结语
通过本文的源码级分析,你应该已经掌握了MyBatis从SqlSession到JDBC的完整执行链路。理解这些底层原理不仅能帮助你在遇到问题时快速定位,更能让你在复杂业务场景下做出更合理的设计决策。下次当你使用MyBatis时,不妨在脑海中回想这个执行流程,相信你会对它有全新的认识。