下面是 MyBatis 与 Spring 集成原理 的深入剖析,涵盖集成方式、核心组件、源码机制以及如何实现无缝协作。MyBatis 本身是独立的持久层框架,通过与 Spring 集成,实现了 依赖注入、事务管理、Mapper 自动注册 等企业级能力。
🌐 一、MyBatis 与 Spring 集成的目标
| 功能 | 原生 MyBatis | 集成 Spring 后 |
|---|---|---|
| SqlSession 管理 | 手动创建/关闭 | 自动管理(SqlSessionTemplate) |
| Mapper 使用 | sqlSession.getMapper() | 注入 Mapper 接口(@Autowired) |
| 事务管理 | 手动提交/回滚 | 与 Spring 事务同步(@Transactional) |
| 配置方式 | mybatis-config.xml + 手动构建 | Spring Bean 配置或 @Configuration |
| 生命周期管理 | 开发者负责 | 由 Spring 容器管理 |
✅ 集成后:开发者不再直接操作
SqlSessionFactory和SqlSession,而是像使用 Service 一样使用 Mapper。
🧩 二、集成方式(常用两种)
方式 1:使用 mybatis-spring 桥接包(推荐)
引入依赖:
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>3.0.3</version>
</dependency>
Spring 配置(Java Config):
@Configuration
@MapperScan("com.example.mapper") // 自动扫描 Mapper 接口
public class MyBatisConfig {
@Bean
public DataSource dataSource() {
return new HikariDataSource(); // 或 Druid、C3P0 等
}
@Bean
public SqlSessionFactory sqlSessionFactory() throws Exception {
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
factoryBean.setDataSource(dataSource());
factoryBean.setMapperLocations(new ClassPathResource("mapper/*.xml"));
return factoryBean.getObject();
}
// 可省略:SqlSessionTemplate 和 Mapper 自动注册
}
🔧 三、核心集成组件与原理
1. SqlSessionFactoryBean —— 创建 SqlSessionFactory
- 实现
FactoryBean<SqlSessionFactory>,Spring 调用getObject()返回SqlSessionFactory。 - 内部封装了原生 MyBatis 的
XMLConfigBuilder和XMLMapperBuilder,完成配置解析。
📌 相当于把
new SqlSessionFactoryBuilder().build(inputStream)这一步交给 Spring 管理。
2. MapperScannerConfigurer 或 @MapperScan —— 自动注册 Mapper
- Spring 启动时扫描指定包下的所有 Mapper 接口。
- 为每个接口生成一个
MapperFactoryBean或直接注册代理对象。 - 最终将 Mapper 代理注入到 IOC 容器中,支持
@Autowired。
@Autowired
private UserMapper userMapper; // 实际是 JDK 动态代理对象
原理流程:
@ComponentScan
↓
@MapperScan → MapperScannerRegistrar → ImportBeanDefinitionRegistrar
↓
注册 Mapper 接口为 BeanDefinition(类型为 MapperFactoryBean)
↓
Spring 实例化时调用 MapperFactoryBean.getObject() → 获取代理对象
3. SqlSessionTemplate —— 线程安全的 SqlSession
- 原生
SqlSession是非线程安全的,不能放入 Spring 容器作为单例。 SqlSessionTemplate是线程安全的,是SqlSession的代理类,内部通过ThreadLocal获取当前事务绑定的SqlSession。
核心特性:
- 使用
Proxy代理所有方法调用。 - 与 Spring 的事务管理器(
DataSourceTransactionManager)协同工作。 - 自动从
TransactionSynchronizationManager获取当前事务的SqlSession。
✅ 保证:同一个事务中,多次调用
getMapper()返回的是同一个SqlSession。
4. SqlSessionUtils —— 与 Spring 事务集成的工具类
- 在执行
sqlSession.select/update/insert/delete前,调用SqlSessionUtils.getSqlSession()。 - 该方法会:
- 检查当前是否有事务绑定的
SqlSession。 - 若有,复用;若无,创建新的并注册到事务同步器。
- 检查当前是否有事务绑定的
- 提交事务时,Spring 会回调
SqlSessionUtils.closeSqlSession()。
5. 事务集成:DataSourceTransactionManager + SqlSession
当使用 @Transactional 时:
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
@Transactional
public void saveUser() {
userMapper.insert(new User("Alice"));
userMapper.updateStatus(1); // 同一个 SqlSession
}
}
事务流程:
@Transactional 开启
↓
TransactionManager 触发 doBegin()
↓
绑定 DataSource 和 Connection 到 ThreadLocal
↓
SqlSessionTemplate 检测到事务,复用该 Connection
↓
所有 Mapper 调用共享同一个 SqlSession 和 Connection
↓
@Transactional 结束 → 提交或回滚
📈 四、集成架构图(Mermaid)
graph TD
A[Spring IOC 容器] --> B[SqlSessionFactoryBean]
A --> C[MapperScannerConfigurer]
A --> D[DataSourceTransactionManager]
B --> E[SqlSessionFactory]
E --> F[SqlSessionTemplate]
F --> G[SqlSession (ThreadLocal)]
C --> H[Mapper 接口]
H --> I[MapperProxy 动态代理]
I --> F
D --> G
G --> J[(Database)]
subgraph "Spring 管理"
A; B; C; D; F
end
subgraph "MyBatis 核心"
E; I; G
end
🔍 五、关键源码入口(可调试点)
| 类名 | 作用 |
|---|---|
SqlSessionFactoryBean.java | 构建 SqlSessionFactory |
MapperScannerRegistrar.java | 处理 @MapperScan 注解 |
MapperFactoryBean<T> | 为每个 Mapper 接口创建代理对象 |
SqlSessionTemplate.java | 线程安全的 SqlSession 代理 |
SqlSessionUtils.java | 与 Spring 事务集成的核心工具 |
MyBatisAutoConfiguration.java(Spring Boot) | 自动配置类 |
✅ 六、Spring Boot 中的自动配置(简化版)
在 Spring Boot 中,只需引入:
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>3.0.3</version>
</dependency>
自动配置生效:
- 自动创建
SqlSessionFactory - 自动扫描
@Mapper或指定包 - 自动配置
SqlSessionTemplate - 支持
@MapperScan和@Mapper注解
配置文件 application.yml:
mybatis:
mapper-locations: classpath:mapper/*.xml
type-aliases-package: com.example.entity
🧠 七、常见问题与最佳实践
| 问题 | 解决方案 |
|---|---|
Invalid bound statement (not found) | 检查 Mapper 接口与 XML 的 namespace 和 id 是否匹配 |
| 事务不生效 | 确保使用 @Transactional 在 Service 层,且类被 Spring 管理 |
| 一级缓存跨事务共享 | 不会,因为 SqlSession 在事务结束后关闭 |
| 多数据源支持 | 使用 AbstractRoutingDataSource + @DS 切换数据源 |
✅ 总结:MyBatis 与 Spring 集成的本质
MyBatis + Spring = SQL 控制力 + 容器管理 + 事务统一
| 核心机制 | 说明 |
|---|---|
| Bean 化 | SqlSessionFactory、Mapper 都作为 Spring Bean 管理 |
| 代理注入 | Mapper 接口通过动态代理自动注入 IOC 容器 |
| 事务同步 | 借助 SqlSessionTemplate 和 TransactionSynchronization 实现事务一致性 |
| 开箱即用 | Spring Boot 更是做到“零配置”集成 |

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



