值得一提的是,SpringManagedTransaction 中除了维护事务关联的数据库连接和数据源之外,还维护了一个 isConnectionTransactional 字段(boolean 类型)用来标识当前事务是否由 Spring 的事务管理器管理,这个标识会控制 commit() 方法和rollback() 方法是否真正提交和回滚事务,相关的代码片段如下:
public void commit() throws SQLException { if (this.connection != null && !this.isConnectionTransactional && !this.autoCommit){ // 当事务不由Spring事务管理器管理的时候,会立即提交事务,否则由Spring事务管理器管理事务的提交和回滚 this.connection.commit(); } } 总结看一眼Xml方式的Spring整合MyBatis,通过两个核心的组件就完成了Spring整合MyBatis。
<!-- 省略 --> <bean> <property ref="dataSource"/> </bean> <bean> <!--:(起始)包名, 从这个包开始扫描--> <property value="com.deepz.mapper"/> </bean> <!-- 省略 -->总结下本文的内容吧:
回顾了MyBatis的相关概念:SqlSessionFactory、SqlSession、Mapper
回顾了Spring的相关概念:FactoryBean、InitializingBean、BeanDefinitionRegistryPostProcessor、BeanFactoryPostProcessor
跟进Spring整合MyBatis的两个重要步骤:1. SqlSessionFactory的维护 2. Mapper的维护
最后还提了一下事务管理器的变化,毕竟是被Spring整合了,事务自然也得交给Spring管理
SqlSessionFactory的注入:
SqlSessionFactoryBean中的buildSqlSessionFactory()会读取MyBatis的核心配置载入内存,并构建出SqlSessionFactory通过FactoryBean的getObject()交给Spring管理。
而buildSqlSessionFactory()方法的触发时机有两个:1. 在Bean初始化的时候Spring回调InitializingBean的afterProperties();2. FactoryBean的getObject()方法会前置判断SqlSessionFactory是否为空,是空则会调用。
Mapper的注入:
MapperScannerConfigurer在Spring应用上下文启动的时候,在较早的时机回调BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry()方法
通过ClassPathMapperScanner来扫描指定过滤条件(包路径、注解类型...)的类,包装成BeanDefinition注册进容器。
同时将这些BeanDefinition做“加工”处理,就是我们讲的“processBeanDefinitions()”。它主要做的两件事:1. 添加构造函数参数值,将当前BeanDefinition的Class传递进去,作为后续sqlSession.getMapper();的入参。2. 将BeanDefinition中的beanClass替换成MapperFactoryBean.class,使得Spring通过BeanDefinition实例化出来的是MapperFactoryBean,上演了一出狸猫换太子。最后注入进去的又是getObject()中MyBatis根据MapperFactoryBean中的mapperInterface字段创建的代理对象, 完成了将Mapper交给Spring管理的目标。
原创不易,希望对你有帮助。欢迎多多指导和讨论。