转自:http://blog.csdn.net/asdfsadfasdfsa/article/details/52037325
工作中,需要学习一下MyBatis sqlSession的产生过程,翻看了mybatis-spring 的源码,阅读了一些mybatis的相关doc,对mybatis sqlSession有了一些认知和理解,这里简单的总结和整理一下。
首先, 通过翻阅源码,我们来整理一下mybatis进行持久化操作时重要的几个类:
SqlSessionFactoryBuilder:build方法创建SqlSessionFactory实例。
SqlSessionFactory:创建SqlSession实例的工厂。
SqlSession:用于执行持久化操作的对象,类似于jdbc中的Connection。
SqlSessionTemplate:MyBatis提供的持久层访问模板化的工具,线程安全,可通过构造参数或依赖注入SqlSessionFactory实例。
hibernate 是与MyBatis类似的orm框架,这里与Hibernate进行一下对比,Hibernate中对于connection的管理,是通过以下几个重要的类:
SessionFactory:创建Session实例的工厂,类似于MyBatis中的SqlSessionFactory。
Session:用来执行持久化操作的对象,类似于jdbc中的Connection。
HibernateTemplate:Hibernate提供的持久层访问模板化的工具,线程安全,可通过构造参数或依赖注入SessionFactory实例。
在日常的开发中,我们经常需要这样对MyBatis和Spring进行集成,把sqlSessionFactory交给Spring管理,通常情况下,我们这样配置:
< code class = "hljs javascript" style = "" > < bean id = < span class = "hljs-string" style = "" > "sqlSessionFactory" </ span > < span class = "hljs-class" style = "" > < span class = "hljs-keyword" style = "" > class </ span > </ span > = < span class = "hljs-string" style = "" > "org.mybatis.spring.SqlSessionFactoryBean" </ span > > < span class = "xml" style = "" > < span class = "hljs-tag" style = "" > < < span class = "hljs-name" style = "" > property </ span > < span class = "hljs-attr" style = "" > name </ span > = < span class = "hljs-string" style = "" > "dataSource" </ span > < span class = "hljs-attr" style = "" > ref </ span > = < span class = "hljs-string" style = "" > "dataSource" </ span > /> </ span > < span class = "hljs-tag" style = "" > </ < span class = "hljs-name" style = "" > bean </ span > > </ span > </ span > </ code >
通过上面的配置,Spring将自动创建一个SqlSessionFactory对象,其中使用到了org.mybatis.spring.SqlSessionFactoryBean,其 是MyBatis为Spring提供的用于创建SqlSessionFactory的类,将在Spring应用程序的上下文建议一下可共享的 MyBatis SqlSessionFactory实例,我们可以通过依赖注入将SqlSessionFactory传递给MyBatis的一些接口。
如果通过Spring进行事务的管理,我们需要增加Spring注解的事务管理机制,如下配置:
< code class = "hljs javascript" style = "" > < bean id = < span class = "hljs-string" style = "" > "transactionManager" </ span > < span class = "hljs-class" style = "" > < span class = "hljs-keyword" style = "" > class </ span > </ span > = < span class = "hljs-string" style = "" > "org.springframework.jdbc.datasource.DataSourceTransactionManager" </ span > > < span class = "xml" style = "" > < span class = "hljs-tag" style = "" > < < span class = "hljs-name" style = "" > property </ span > < span class = "hljs-attr" style = "" > name </ span > = < span class = "hljs-string" style = "" > "dataSource" </ span > < span class = "hljs-attr" style = "" > ref </ span > = < span class = "hljs-string" style = "" > "dataSource" </ span > /> </ span > < span class = "hljs-tag" style = "" > </ < span class = "hljs-name" style = "" > bean </ span > > </ span > </ span > < tx:annotation-driven /> </ code >
这样,我们就可以使用Spring @Transactional注解,进行事务的控制,表明所注释的方法应该在一个事务中运行。 Spring将在事务成功完成后提交事务,在事务发生错误时进行异常回滚,而且,Spring会将产生的MyBatis异常转换成适当的 DataAccessExceptions,从而提供具体的异常信息。
下面,我们通过分析SqlSessionUtils中getSession的源码,来详细的了解一下sqlSession的产生过程,源码如下:
<code class = "hljs java" style= "" ><span class = "hljs-function" style= "" ><span class = "hljs-keyword" style= "" > public </span> <span class = "hljs-keyword" style= "" > static </span> SqlSession <span class = "hljs-title" style= "" >getSqlSession</span><span class = "hljs-params" style= "" >(SqlSessionFactory sessionFactory, ExecutorType executorType, PersistenceExceptionTranslator exceptionTranslator)</span> </span>{ notNull(sessionFactory, <span class = "hljs-string" style= "" > "No SqlSessionFactory specified" </span>); notNull(executorType, <span class = "hljs-string" style= "" > "No ExecutorType specified" </span>); SqlSessionHolder holder = (SqlSessionHolder) getResource(sessionFactory); <span class = "hljs-keyword" style= "" > if </span> (holder != <span class = "hljs-keyword" style= "" > null </span> && holder.isSynchronizedWithTransaction()) { <span class = "hljs-keyword" style= "" > if </span> (holder.getExecutorType() != executorType) { <span class = "hljs-keyword" style= "" > throw </span> <span class = "hljs-keyword" style= "" > new </span> TransientDataAccessResourceException(<span class = "hljs-string" style= "" > "Cannot change the ExecutorType when there is an existing transaction" </span>); } holder.requested(); <span class = "hljs-keyword" style= "" > if </span> (logger.isDebugEnabled()) { logger.debug(<span class = "hljs-string" style= "" > "Fetched SqlSession [" </span> + holder.getSqlSession() + <span class = "hljs-string" style= "" > "] from current transaction" </span>); } <span class = "hljs-keyword" style= "" > return </span> holder.getSqlSession(); } <span class = "hljs-keyword" style= "" > if </span> (logger.isDebugEnabled()) { logger.debug(<span class = "hljs-string" style= "" > "Creating a new SqlSession" </span>); } SqlSession session = sessionFactory.openSession(executorType); <span class = "hljs-comment" style= "" > <span class = "hljs-comment" style= "" > <span class = "hljs-comment" style= "" > <span class = "hljs-comment" style= "" > <span class = "hljs-comment" style= "" > <span class = "hljs-comment" style= "" > <span class = "hljs-keyword" style= "" > if </span> (isSynchronizationActive()) { Environment environment = sessionFactory.getConfiguration().getEnvironment(); <span class = "hljs-keyword" style= "" > if </span> (environment.getTransactionFactory() <span class = "hljs-keyword" style= "" > instanceof </span> SpringManagedTransactionFactory) { <span class = "hljs-keyword" style= "" > if </span> (logger.isDebugEnabled()) { logger.debug(<span class = "hljs-string" style= "" > "Registering transaction synchronization for SqlSession [" </span> + session + <span class = "hljs-string" style= "" > "]" </span>); } holder = <span class = "hljs-keyword" style= "" > new </span> SqlSessionHolder(session, executorType, exceptionTranslator); bindResource(sessionFactory, holder); registerSynchronization(<span class = "hljs-keyword" style= "" > new </span> SqlSessionSynchronization(holder, sessionFactory)); holder.setSynchronizedWithTransaction(<span class = "hljs-keyword" style= "" > true </span>); holder.requested(); } <span class = "hljs-keyword" style= "" > else </span> { <span class = "hljs-keyword" style= "" > if </span> (getResource(environment.getDataSource()) == <span class = "hljs-keyword" style= "" > null </span>) { <span class = "hljs-keyword" style= "" > if </span> (logger.isDebugEnabled()) { logger.debug(<span class = "hljs-string" style= "" > "SqlSession [" </span> + session + <span class = "hljs-string" style= "" > "] was not registered for synchronization because DataSource is not transactional" </span>); } } <span class = "hljs-keyword" style= "" > else </span> { <span class = "hljs-keyword" style= "" > throw </span> <span class = "hljs-keyword" style= "" > new </span> TransientDataAccessResourceException( <span class = "hljs-string" style= "" > "SqlSessionFactory must be using a SpringManagedTransactionFactory in order to use Spring transaction synchronization" </span>); } } } <span class = "hljs-keyword" style= "" > else </span> { <span class = "hljs-keyword" style= "" > if </span> (logger.isDebugEnabled()) { logger.debug(<span class = "hljs-string" style= "" > "SqlSession [" </span> + session + <span class = "hljs-string" style= "" > "] was not registered for synchronization because synchronization is not active" </span>); } } <span class = "hljs-keyword" style= "" > return </span> session; }</code>
上面的getSession方法,会从Spring的事务管理器中获取一个SqlSession或创建一个新的SqlSession,将试图从当前事务中得到一个SqlSession,然后,如果配置有事务管理器的工厂并且Spring 的事务管理器是活跃的,它将会锁定当前事务的SqlSession,保证同步。主要是通过以下几个步骤进行SqlSession的创建:
它会首先获取SqlSessionHolder,SqlSessionHolder用于在TransactionSynchronizationManager中保持当前的SqlSession。
如果holder不为空,并且holder被事务锁定,则可以通过holder.getSqlSession()方法,从当前事务中获取sqlSession,即 Fetched SqlSession from current transaction。
如果不存在holder或没有被事务锁定,则会创建新的sqlSession,即 Creating a new SqlSession,通过sessionFactory.openSession()方法。
如果当前线程的事务是活跃的,将会为SqlSession注册事务同步,即 Registering transaction synchronization for SqlSession。