SqlSessionDaoSupport是一个抽象的支持类,用来为你提供SqlSession。调用getSqlSession()方法你会得到一个SqlSessionTemplate,这然后可以用于执行SQL方法,首先, 通过翻阅源码,我们来整理一下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管理,通常情况下,我们这样配置:?123通过上面的配置,spring将自动创建一个sqlsessionfactory对象,其中使用到了org.mybatis.spring.sqlsessionfactorybean,其 是mybatis为spring提供的用于创建sqlsessionfactory的类,将在spring应用程序的上下文建议一下可共享的 mybatis sqlsessionfactory实例,我们可以通过依赖注入将sqlsessionfactory传递给mybatis的一些接口。 如果通过spring进行事务的管理,我们需要增加spring注解的事务管理机制,如下配置:?12345这样,我们就可以使用spring @transactional注解,进行事务的控制,表明所注释的方法应该在一个事务中运行。 spring将在事务成功完成后提交事务,在事务发生错误时进行异常回滚,而且,spring会将产生的mybatis异常转换成适当的 dataaccessexceptions,从而提供具体的异常信息。 下面,我们通过分析sqlsessionutils中getsession的源码,来详细的了解一下sqlsession的产生过程,源码如下:public static sqlsession getsqlsession(sqlsessionfactory sessionfactory, executortype executortype, persistenceexceptiontranslator exceptiontranslator) notnull(sessionfactory, "no sqlsessionfactory specified"); notnull(executortype, "no executortype specified"); sqlsessionholder holder = (sqlsessionholder) getresource(sessionfactory); if (holder != null && holder.issynchronizedwithtransaction()) if (holder.getexecutortype() != executortype) throw new transientdataaccessresourceexception("cannot change the executortype when there is an existing transaction"); } holder.requested(); if (logger.isdebugenabled()) logger.debug("fetched sqlsession [" + holder.getsqlsession() + "] from current transaction"); } return holder.getsqlsession(); } if (logger.isdebugenabled()) logger.debug("creating a new sqlsession"); } sqlsession session = sessionfactory.opensession(executortype); // register session holder if synchronization is active (i.e. a spring tx is active) // // note: the datasource used by the environment should be synchronized with the // transaction either through datasourcetxmgr or another tx synchronization. // further assume that if an exception is thrown, whatever started the transaction will // handle closing / rolling back the connection associated with the sqlsession. if (issynchronizationactive()) environment environment = sessionfactory.getconfiguration().getenvironment(); if (environment.gettransactionfactory() instanceof springmanagedtransactionfactory) if (logger.isdebugenabled()) logger.debug("registering transaction synchronization for sqlsession [" + session + "]"); } holder = new sqlsessionholder(session, executortype, exceptiontranslator); bindresource(sessionfactory, holder); registersynchronization(new sqlsessionsynchronization(holder, sessionfactory)); holder.setsynchronizedwithtransaction(true); holder.requested(); } else if (getresource(environment.getdatasource()) == null) if (logger.isdebugenabled()) logger.debug("sqlsession [" + session + "] was not registered for synchronization because datasource is not transactional"); } } else throw new transientdataaccessresourceexception( "sqlsessionfactory must be using a springmanagedtransactionfactory in order to use spring transaction synchronization"); } } } else if (logger.isdebugenabled()) logger.debug("sqlsession [" + session + "] was not registered for synchronization because synchronization is not active"); } } return session;}上面的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。
工作中,需要学习一下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管理,通常情况下,我们这样配置:
?
1
2
3
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
</bean>
通过上面的配置,Spring将自动创建一个SqlSessionFactory对象,其中使用到了org.mybatis.spring.SqlSessionFactoryBean,其 是MyBatis为Spring提供的用于创建SqlSessionFactory的类,将在Spring应用程序的上下文建议一下可共享的 MyBatis SqlSessionFactory实例,我们可以通过依赖注入将SqlSessionFactory传递给MyBatis的一些接口。
如果通过Spring进行事务的管理,我们需要增加Spring注解的事务管理机制,如下配置:
?
1
2
3
4
5
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<tx:annotation-driven/>
这样,我们就可以使用Spring @Transactional注解,进行事务的控制,表明所注释的方法应该在一个事务中运行。 Spring将在事务成功完成后提交事务,在事务发生错误时进行异常回滚,而且,Spring会将产生的MyBatis异常转换成适当的 DataAccessExceptions,从而提供具体的异常信息。
下面,我们通过分析SqlSessionUtils中getSession的源码,来详细的了解一下sqlSession的产生过程,源码如下:
public static SqlSession getSqlSession(SqlSessionFactory sessionFactory, ExecutorType executorType, PersistenceExceptionTranslator exceptionTranslator) {
notNull(sessionFactory, "No SqlSessionFactory specified");
notNull(executorType, "No ExecutorType specified");
SqlSessionHolder holder = (SqlSessionHolder) getResource(sessionFactory);
if (holder != null && holder.isSynchronizedWithTransaction()) {
if (holder.getExecutorType() != executorType) {
throw new TransientDataAccessResourceException("Cannot change the ExecutorType when there is an existing transaction");
}
holder.requested();
if (logger.isDebugEnabled()) {
logger.debug("Fetched SqlSession [" + holder.getSqlSession() + "] from current transaction");
}
return holder.getSqlSession();
}
if (logger.isDebugEnabled()) {
logger.debug("Creating a new SqlSession");
}
SqlSession session = sessionFactory.openSession(executorType);
// Register session holder if synchronization is active (i.e. a Spring TX is active)
//
// Note: The DataSource used by the Environment should be synchronized with the
// transaction either through DataSourceTxMgr or another tx synchronization.
// Further assume that if an exception is thrown, whatever started the transaction will
// handle closing / rolling back the Connection associated with the SqlSession.
if (isSynchronizationActive()) {
Environment environment = sessionFactory.getConfiguration().getEnvironment();
if (environment.getTransactionFactory() instanceof SpringManagedTransactionFactory) {
if (logger.isDebugEnabled()) {
logger.debug("Registering transaction synchronization for SqlSession [" + session + "]");
}
holder = new SqlSessionHolder(session, executorType, exceptionTranslator);
bindResource(sessionFactory, holder);
registerSynchronization(new SqlSessionSynchronization(holder, sessionFactory));
holder.setSynchronizedWithTransaction(true);
holder.requested();
} else {
if (getResource(environment.getDataSource()) == null) {
if (logger.isDebugEnabled()) {
logger.debug("SqlSession [" + session + "] was not registered for synchronization because DataSource is not transactional");
}
} else {
throw new TransientDataAccessResourceException(
"SqlSessionFactory must be using a SpringManagedTransactionFactory in order to use Spring transaction synchronization");
}
}
} else {
if (logger.isDebugEnabled()) {
logger.debug("SqlSession [" + session + "] was not registered for synchronization because synchronization is not active");
}
}
return session;
}
上面的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。