1.2.1、框架
Spring3+Mybatis3+Mybatis-spring-1.1.1
针对框架简单说几句,主要是为什么要做整合,方便后续的认知。
1、 Mybatis的sqlsession是否是线程安全的?为什么?
a) DefaultSqlSession是经常看到的一个实现类,源码中官方标注是线程不安全的
b) 因为当并发操作同一个DefaultSqlSession的时候拿到的具体Executor同样是同一个,其中会getConnection获取到同一个连接,那么在ThreadA做新增操作时,此时ThreadB正在做删除操作,ThreadAconnection执行完毕后会提交事务,将ThreadB操作一并提交,ThreadA再次查询时,导致ThreadA出现了脏读的现象。其次在一级缓存中也有可能出现转换类型的错误。
2、 spring整合mybatis如何做到保持sqlSession线程安全?

(对应附件spring整合mybatis保证session安全简版.svg)
将sqlSessionTemplate代替DefaultSqlSession操作,这样会到一个jdk代理中,代理第一步获取session的时候就会查找当前线程的事务中是否有session,如果有就直接取出来用,做到线程之间的session隔离。该查询请求结束时,只是记录holder中session调用,不会真的提交,做到事务的整体控制。
1.2.2、启动加载(仅描述部分相关bean加载)
dynamicDataSource:将所有数据源进行加载和映射存储,并设置好默认数据源,该类自身就可以看作一个DataSource。
sqlSessionFactory:mybatis的sql操作都是由sqlSessionFactory的openSession取得的sqlSession进行db操作的,所以涉及到的数据源就加载了dynamicDataSource动态数据源。并且注意,注入的class是org.mybatis.spring.SqlSessionFactoryBean,可以看到已经是mybatis和spring的整合包内容,相当于内容已经开始整合,其次可以看到这是一个FactoryBean,实现了FactoryBean接口,会在IOC初始化实例的时候自行做一些操作,生产出合适的sqlSessionFactory,其中值得注意的是其中的afterPropertiesSet方法,在init初始化该bean的属性值之后,便会调用该方法,其中有这么一个创建this.transactionFactory = new SpringManagedTransactionFactory();将事务托付给了spring。这个类很重要,之后会遇到。
transactionManager:spring提供的事务管理,与Mybatis整合后使用到的是DataSourceTransactionManager,该类同样要依赖数据源,所以同样注入dynamicDataSource动态数据源。
TransactionSynchronizationManager:该类全程参与事务上下文的信息同步管理,包括之前所说holder也就是从该类中获取(本质上就是一个线程变量ThreadLocal > resources )。
TransactionInterceptor:要知道spring要做到声明式事务管理,是内置了一个Interceptor的,具体作用就是判断请求的methodName是否需要事务管理从而对。
BaseDao:加载类BaseDaoImpl,该类继承了SqlSessionDaoSupport类,在注入sqlSessionFactory的时候就实例化了sqlSessionTemplate,也将sqlSessionProxy进行了实例化。
1.2.3、请求处理流程
首先注意:openSession并不是在真正获取数据库连接,只是在应用侧开启会话对象,填充事务、执行器等必要的参数。真正获取连接是在executor的preperstatment的getConnection时候,才真正获取到了数据库连接(即多数据源切换得重点在于getConnection这一步)。

Ps:橙色:我们手写的业务、工具类
红色:Spring提供的类
蓝色:Mybatis提供的类
紫色:mybatis-spring整合类提供的类
(对应附件事务与多数据源处理过程.svg)
该时序图已经很详细叙述了数据源切换的位置(12-16)以及事务判断的位置和作用,故不再文字赘述(若有疑问可自行追寻源码分析)。