14.MyBatis执行流程

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. 类型转换(TypeHandler3. 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的执行流程可以概括为三个关键点:

  1. 初始化建工厂:解析配置,构建SqlSessionFactory
  2. 运行时走代理:通过动态代理执行Mapper方法
  3. 核心靠Executor:由Executor协调StatementHandler、ParameterHandler、ResultSetHandler完成SQL执行

掌握MyBatis的执行原理不仅有助于解决日常开发中的问题,更能为性能优化和深度定制提供理论基础。建议结合源码阅读,深入理解每个组件的职责和协作方式。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值