在Mybatis中SqlSessionFactory负责创建SqlSession,一旦创建成功,就可以用SqlSession实例来执行映射语句,commit,rollback,close等方法。但当使用Mybatis-Spring时beans将会注入一个线程安全的SqlSession并通过Spring的事务管理自动commit,rollback,close。

 

 

通常我们通过对SqlSessionDaoSupport类的继承,然后通过getSession()方法来获取session,但需要注入:sqlSessionFactory或sqlSessionTemplate,那么sqlSessionFactory和sqlSessionTemplate有什么区别呢?

首先这里先来看【SqlSessionDaoSupport】的源代码:

/*
 *    Copyright 2010 The myBatis Team
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package org.mybatis.spring.support;
 
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.support.DaoSupport;
import org.springframework.util.Assert;
 
/**
ta access objects.
 * It gives you access to the template which can then be used to execute SQL methods.
 * <p>
 * This class needs a SqlSessionTemplate or a SqlSessionFactory.
 * If both are set the SqlSessionFactory will be ignored.
 *
 * @see #setSqlSessionFactory
 * @see #setSqlSessionTemplate
 * @see SqlSessionTemplate
 * @version $Id: SqlSessionDaoSupport.java 3266 2010-11-22 06:56:51Z simone.tripodi $
 */
public abstract  class SqlSessionDaoSupport extends DaoSupport {
 
// 这个SqlSession就是我们平时用来执行SQL和事务的一次会话
    private SqlSession sqlSession;
 
private boolean
 
// 可以看到以下两个Autowired的set方法,实际上他们的功能都是设置sqlSession的实例
    // 区别在于一个是通过传入sqlSessionFactory然后包装成SqlSessionTemplate
    // 另一个直接传入SqlSessionTemplate赋值给sqlSession
    @Autowired(required = false)
public final  void
if (!this.externalSqlSession) {
this.sqlSession = new
        }
    }
 
= false)
public final  void
this.sqlSession =
this.externalSqlSession = true;
    }
 
/**
     * Users should use this method to get a SqlSession to call its statement methods
     * This is SqlSession is managed by spring. Users should not commit/rollback/close it
     * because it will be automatically done.
     *
     * @return Spring managed thread safe SqlSession 
     */
    public final SqlSession getSqlSession() {
return this.sqlSession;
    }
 
/**
     * {@inheritDoc}
     */
    protected void checkDaoConfig() {
this.sqlSession, "Property 'sqlSessionFactory' or 'sqlSessionTemplate' are required");
    }
 
}

通过源码我们可以看到其实:sqlSessionFactory注入,最终还是被包装为:sqlSessionTemplate,因此,在继承SqlSessionDaoSupport类,注入sqlSessionFactory或sqlSessionTemplate,原理上时一致的。

另外通过源码的getSession方法的注释我们可以看到,使用spring管理session,我们不能提交、回滚和关闭session,因为Spring已对其进行线程安全管理。

附:spring-mybatis配置文件:

 

<!-- 配置数据源 -->
    <bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
       <property  name="jndiName"  value="java:comp/env/jdbc/bmc" />
       <!--property name="jndiName" value="bmc" / -->
    </bean>
    <!-- sqlSessionFactory配置 -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
       <property  name="configLocation"  value="classpath:mybatis-config.xml" />
       <property  name="mapperLocations"  value="classpath:BMC_*.xml" />
       <property  name="dataSource"  ref="dataSource"  />
    </bean>
    <!-- sqlSessionTemplate配置(支持批量) -->
    <bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
       <!-- 参数1: sqlSessionFactory|参数2:ExecutorType -->
       <constructor-arg  index="0"  ref="sqlSessionFactory"  />
       <constructor-arg  index="1"  value="BATCH"  />
    </bean>

注意:

①:在继承SqlSessionDaoSupport类,无论你是通过[sqlSessionFactory]注入还是通过[sqlSessionTemplate]注入,spring均会对session自动管理,因此您不能通过getSession()获取的session进行提交、回滚、关闭操作。

②:如果没继承SqlSessionDaoSupport类,需要对session自行管理。

 

总结:

       上文仅对继承SqlSessionDaoSupport类并通过getSession()方法获取session时,不能对该session进行提交、回滚、关闭操作,因为Spirng已经帮其自动管理。本来文章想说明事务相关的内容,因为在网上看了很多文章说:{使用Mybatis-Spring时beans将会注入一个线程安全的SqlSession并通过Spring的事务管理自动commit,rollback,close。},但本人自己调试程序发现如下日志:

SqlSessionUtils:46 - Creating a new SqlSession
SqlSessionUtils:46 - SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1d183b7] was not registered for synchronization because synchronization is not active
DataSourceUtils:110 - Fetching JDBC Connection from DataSource
SpringManagedTransaction:46 - JDBC Connection [jdbc:oracle:thin:@127.0.0.1:1521:bmcdb, UserName=BMC, Oracle JDBC driver] will not be managed by Spring
findRescByRoleID:46 - ooo Using Connection [jdbc:oracle:thin:@127.0.0.1:1521:bmcdb, UserName=BMC, Oracle JDBC driver]
findRescByRoleID:46 - ==>  Preparing: SELECT R.RESCID,R.RESCTYPE,R.RESCNAME,R.RESCURL FROM BMC_RESOURCE R LEFT JOIN BMC_ROLE_RESOURCE RR ON R.RESCID = RR.RESCID WHERE RR.ROLEID = ? 
findRescByRoleID:46 - ==> Parameters: ST00004G(String)
findRescByRoleID:46 - <==      Total: 0
SqlSessionUtils:46 -  Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1d183b7]
DataSourceUtils:327 - Returning JDBC Connection to DataSource

通过日志的红色部分,我们可以看到,其含义为:

①:【SqlSession: was not registered for synchronization because synchronization is not active】同步未注册,因为同步是不可行的;

②:【JDBC Connection:will not be managed by Spring】事务没有被Spring管理;

③:【Closing non transactional SqlSession】关闭没有非事务的SqlSession。

但如果对datasource在spring 配置文件中加入事务管理配置,上述日志将会有变化,但由于自己还没有弄懂,所以这里先不做说明,待自己弄懂之后再进述。