本文概览:本文深入解析MyBatis与Spring的整合全流程,从原生MyBatis执行流程入手,逐步剖析SqlSessionFactoryBean、MapperScannerConfigurer等核心整合机制,揭示Spring如何接管MyBatis组件的生命周期管理


原生 MyBatis 的执行流程

在未整合 Spring 时,MyBatis 的使用需要手动管理所有资源:

  1. 创建 SqlSessionFactory(工厂)首先需要加载 MyBatis 配置文件,通过 SqlSessionFactoryBuilder 构建一个 SqlSessionFactory 对象。这个工厂是单例的,负责创建后续的 SqlSession,整个应用生命周期内只需要初始化一次
  2. 获取 SqlSession(数据库会话窗口)每次需要操作数据库时,都要通过工厂的 openSession() 方法手动创建一个 SqlSession。SqlSession 代表一次与数据库的会话,内部封装了数据库连接、执行器和事务管理器。它是非线程安全的,每次数据库操作都需要独立创建
  3. 获取 Mapper 代理对象通过 SqlSession 的 getMapper() 方法,传入 Mapper 接口的 Class 对象,MyBatis 会利用动态代理技术为这个接口生成一个实现类。这个代理对象内部持有 SqlSession 的引用,但本身不包含业务逻辑
  4. 执行并释放资源调用 Mapper 代理对象的方法执行数据库操作后,必须手动提交事务(commit)或回滚(rollback),最后手动关闭 SqlSession释放数据库连接。如果忘记关闭,会导致连接泄漏

Spring 整合 MyBatis 后的流程

整合后,Spring 接管了所有资源管理,开发者只需关注业务逻辑:

  1. Spring 启动时自动初始化应用启动时,Spring 通过扫描注解自动发现所有的 Mapper 接口,为每个接口创建对应的代理对象并注册到 Spring 容器中。同时,SqlSessionFactory 也被创建为 Spring 的单例 Bean
  2. 调用 Mapper 方法时自动处理开发者通过依赖注入获得 Mapper 接口的引用(实际上是代理对象),直接调用方法即可。这个代理对象在方法被调用时,会自动从 Spring 的事务上下文中获取 SqlSession。如果当前存在事务,则复用已绑定的 SqlSession;如果没有事务,则临时创建一个新的
  3. SqlSession 的自动化管理Spring 使用 SqlSessionTemplate 对 SqlSession 进行封装,这是一个线程安全的代理。它内部会拦截所有 SqlSession 的操作,自动处理事务的提交或回滚、异常转换为 Spring 统一的异常体系,并在操作完成后自动关闭 SqlSession,避免资源泄漏

Mybatis数据库操作的完整流程

第 1 步:应用启动时 —— 构建核心基础设施

  1. Spring 创建DataSourceBean通常由 Spring Boot 自动配置(如 HikariCP、Druid)负责管理数据库连接池,提供java.sql.Connection
  2. Spring 创建SqlSessionFactoryBean@Bean
    public SqlSessionFactory sqlSessionFactory(DataSource dataSource) {
    SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
    factory.setDataSource(dataSource); // ← 关键绑定!
    return factory.getObject();
    }SqlSessionFactory持有对DataSource的引用加载所有 Mapper XML / 注解,解析为MappedStatement,存入内部的Configuration对象此时SqlSessionFactory已具备“执行任意 SQL”的能力,但尚未创建连接
  3. Spring 扫描 Mapper 接口,注册代理 Bean通过@MapperScan,MyBatis-Spring 为每个接口生成一个MapperFactoryBean该 FactoryBean 在getObject()时返回一个动态代理对象(MapperProxy)这个代理对象内部持有SqlSessionTemplate(而SqlSessionTemplate持有SqlSessionFactory)

至此,依赖链建立完成:

Mapper Proxy → SqlSessionTemplate → SqlSessionFactory → DataSource

第 2 步:业务代码调用 Mapper 方法

1
User user = userMapper.selectById(1L);

→ 实际调用的是JDK 动态代理的invoke()方法

第 3 步:MapperProxy.invoke()拦截调用

  • 将方法调用封装为MapperMethod
  • 调用mapperMethod.execute(sqlSession, args)
  • 这里的sqlSession是SqlSessionTemplate(线程安全的代理)

第 4 步:SqlSessionTemplate获取真正的SqlSession

  • SqlSessionTemplate不是真正的SqlSession,而是一个代理/装饰器;
  • 作用:检查当前线程是否有 Spring 管理的事务(TransactionSynchronizationManager)如果有 → 复用已存在的SqlSession(保证事务一致性)如果没有 → 调用sqlSessionFactory.openSession()创建新会话
  • 关键点:sqlSessionFactory.openSession()内部会:创建一个Transaction(如SpringManagedTransaction或JdbcTransaction)该 Transaction 从DataSource中获取一个Connection将Connection封装进Executor,再包装成DefaultSqlSession

此刻,SqlSession才真正拥有了数据库连接!

第 5 步:执行 SQL(通过DataSource提供的连接)

  • SqlSession.selectOne("com.example.UserMapper.selectById", 1)
  • 根据 ID 从Configuration中找到对应的MappedStatement
  • 使用PreparedStatementHandler执行 SQL:Connection conn = transaction.getConnection(); // ← 来自 DataSource!
    PreparedStatement ps = conn.prepareStatement(sql);
    // 设置参数、执行、获取 ResultSet...
  • 结果集通过ResultMap映射为 Java 对象(如User)

第 6 步:返回结果 & 释放资源

  • 如果是非事务方法:SqlSessionTemplate在方法结束后自动关闭SqlSessionConnection被归还给DataSource的连接池
  • 如果是@Transactional方法:Connection保持打开,直到事务提交/回滚事务结束时,Spring 通知DataSource归还连接

全局视角:各组件角色总结

组件 角色 在流程中的作用
DataSource 数据库连接提供者 提供Connection,决定连接池、URL、账号等;所有 SQL 最终通过它执行
SqlSessionFactory SqlSession工厂 持有DataSource+Configuration(含所有 SQL 映射);负责创建SqlSession
SqlSession SQL 执行器 持有Connection,执行具体 SQL,管理本地缓存、事务状态
Mapper Proxy 接口调用桥梁 将userMapper.selectById()转为sqlSession.selectOne(...)
Spring 协调者 管理 Bean 生命周期、事务、线程绑定,确保SqlSession与DataSource正确协作

核心对比

环节 原生 MyBatis Spring 整合后
SqlSessionFactory 手动创建单例 Spring 容器自动管理
SqlSession 获取 手动 openSession() 自动从事务上下文获取
Mapper 代理 手动 getMapper() Spring 自动注入
事务管理 手动 commit/rollback Spring 声明式事务管理
资源释放 手动 close() Spring 自动关闭
异常处理 MyBatis 原生异常 自动转为 Spring 统一异常

版权声明:本文为CSDN博主「青山木」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/LI_124301012/article/details/159828465