MyBatis执行流程深度解析:从配置文件到SQL执行
1. 核心思想:MyBatis如何工作?
一句话总结:MyBatis通过XML配置将SQL语句与Java对象映射绑定,利用动态代理机制执行数据库操作。
执行流程两大阶段:
- 初始化阶段:项目启动时加载配置,构建核心工厂
- 运行时阶段:通过代理对象执行具体的SQL操作
2. 初始化阶段:配置加载与解析
2.1 配置加载过程
// 初始化流程伪代码
1. 解析mybatis-config.xml → Configuration对象
2. 加载所有Mapper XML文件 → MappedStatement集合
3. 数据源、插件、别名等配置注入
4. 构建SqlSessionFactory(核心工厂)
2.2 关键组件初始化
<!-- mybatis-config.xml 核心配置 -->
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/test"/>
<property name="username" value="root"/>
<property name="password" value="password"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="com/example/mapper/UserMapper.xml"/>
</mappers>
</configuration>
2.3 MappedStatement存储
每条SQL语句被解析为MappedStatement对象:
- id:SQL语句标识
- sqlSource:SQL内容
- parameterType:参数类型
- resultType:返回类型
- statementType:语句类型(PREPARED、CALLABLE等)
3. 运行时阶段:SQL执行流程
3.1 获取SqlSession
// 获取SqlSession流程
SqlSessionFactory factory = sqlSessionFactoryBuilder.build(inputStream);
SqlSession session = factory.openSession();
3.2 动态代理机制
Mapper接口没有实现类,MyBatis通过JDK动态代理生成代理对象:
public class MapperProxy implements InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args) {
// 1. 根据方法名找到对应的MappedStatement
// 2. 调用Executor执行SQL
// 3. 返回处理结果
}
}
3.3 执行器(Executor)工作流程
1. StatementHandler → 准备Statement
2. ParameterHandler → 绑定参数
3. ResultSetHandler → 映射结果
4. 事务提交/回滚控制
4. 核心组件深度解析
4.1 Executor执行器体系
// Executor继承体系
Executor (接口)
↑
BaseExecutor (抽象类)
↑
SimpleExecutor (简单执行器)
BatchExecutor (批量执行器)
ReuseExecutor (复用执行器)
CachingExecutor (缓存执行器)
4.2 StatementHandler详解
public interface StatementHandler {
Statement prepare(Connection connection) throws SQLException;
void parameterize(Statement statement) throws SQLException;
int update(Statement statement) throws SQLException;
<E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException;
}
4.3 参数处理流程
// ParameterHandler工作流程
1. 解析方法参数 @Param注解
2. 类型转换(TypeHandler)
3. PreparedStatement参数设置
4.4 结果集映射
// ResultSetHandler工作流程
1. 遍历ResultSet
2. 使用TypeHandler进行类型转换
3. 对象属性填充(支持嵌套映射)
4. 返回List或单个对象
5. 完整执行流程示例
5.1 代码示例
// 用户调用代码
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
User user = userMapper.selectById(1);
// MyBatis内部执行流程:
1. MapperProxy.invoke("selectById", 1)
2. 找到MappedStatement("selectById")
3. Executor执行查询
4. StatementHandler准备PreparedStatement
5. ParameterHandler设置参数:setInt(1, 1)
6. 执行查询,获取ResultSet
7. ResultSetHandler映射结果集→User对象
8. 返回结果
5.2 XML配置对应
<!-- UserMapper.xml -->
<mapper namespace="com.example.mapper.UserMapper">
<select id="selectById" resultType="User">
SELECT * FROM users WHERE id = #{id}
</select>
</mapper>
6. 高级特性与优化
6.1 插件机制(Interceptor)
// 自定义插件示例
@Intercepts({
@Signature(type = Executor.class, method = "query",
args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})
})
public class QueryInterceptor implements Interceptor {
public Object intercept(Invocation invocation) throws Throwable {
// 前置处理
Object result = invocation.proceed();
// 后置处理
return result;
}
}
6.2 缓存机制
一级缓存:SqlSession级别(默认开启)
二级缓存:Mapper级别(需要配置开启)
6.3 延迟加载
<!-- 延迟加载配置 -->
<settings>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
7. 性能优化建议
7.1 配置优化
<settings>
<!-- 批量操作 -->
<setting name="defaultExecutorType" value="BATCH"/>
<!-- 缓存配置 -->
<setting name="localCacheScope" value="STATEMENT"/>
<!-- 结果集处理 -->
<setting name="defaultFetchSize" value="100"/>
</settings>
7.2 SQL编写优化
<!-- 避免N+1查询 -->
<select id="selectUserWithOrders" resultMap="userWithOrders">
SELECT u.*, o.*
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
WHERE u.id = #{id}
</select>
8. 常见问题与解决方案
8.1 参数映射问题
// 正确使用@Param注解
User selectByUsernameAndEmail(@Param("username") String username,
@Param("email") String email);
8.2 结果映射问题
<!-- 使用resultMap解决复杂映射 -->
<resultMap id="userResultMap" type="User">
<id property="id" column="user_id"/>
<result property="username" column="user_name"/>
<collection property="orders" ofType="Order">
<id property="id" column="order_id"/>
</collection>
</resultMap>
9. 最佳实践总结
9.1 代码组织规范
src/
├── main/
│ ├── java/
│ │ └── com/example/
│ │ ├── entity/ # 实体类
│ │ ├── mapper/ # Mapper接口
│ │ └── service/ # 业务层
│ └── resources/
│ ├── mybatis-config.xml # 主配置
│ └── com/example/mapper/ # Mapper XML文件
9.2 配置管理规范
# 建议的配置分离
- mybatis-config-core.xml # 核心配置
- mybatis-config-datasource.xml # 数据源配置
- mybatis-config-mappers.xml # Mapper配置
9.3 性能监控建议
// 添加监控拦截器
public class MonitorInterceptor implements Interceptor {
public Object intercept(Invocation invocation) throws Throwable {
long start = System.currentTimeMillis();
Object result = invocation.proceed();
long end = System.currentTimeMillis();
// 记录执行时间超过100ms的SQL
if (end - start > 100) {
log.warn("Slow SQL: {}ms, {}", (end - start), getSqlInfo(invocation));
}
return result;
}
}
10. 总结
MyBatis的执行流程可以概括为三个关键点:
- 初始化建工厂:解析配置,构建SqlSessionFactory
- 运行时走代理:通过动态代理执行Mapper方法
- 核心靠Executor:由Executor协调StatementHandler、ParameterHandler、ResultSetHandler完成SQL执行
掌握MyBatis的执行原理不仅有助于解决日常开发中的问题,更能为性能优化和深度定制提供理论基础。建议结合源码阅读,深入理解每个组件的职责和协作方式。
998

被折叠的 条评论
为什么被折叠?



