一.摘要
这篇文章将介绍Spring整合Mybatis 如何完成SqlSessionFactory的动态切换的。并且会简单的介绍下MyBatis整合Spring中的官方的相关代码。
Spring整合MyBatis切换SqlSessionFactory有两种方法,第一、 继承SqlSessionDaoSupport,重写获取SqlSessionFactory的方法。第二、继承SqlSessionTemplate 重写getSqlSessionFactory、getConfiguration和SqlSessionInterceptor这个拦截器。其中最为关键还是继承SqlSessionTemplate 并重写里面的方法。
而Spring整合MyBatis也有两种方式,一种是配置MapperFactoryBean,另一种则是利用MapperScannerConfigurer进行扫描接口或包完成对象的自动创建。相对来说后者更方便些。MapperFactoryBean继承了SqlSessionDaoSupport也就是动态切换SqlSessionFactory的第一种方法,我们需要重写和实现SqlSessionDaoSupport方法,或者是继承MapperFactoryBean来重写覆盖相关方法。如果利用MapperScannerConfigurer的配置整合来切换SqlSessionFactory,那么我们就需要继承SqlSessionTemplate,重写上面提到的方法。在整合的配置中很多地方都是可以注入SqlSessionTemplate代替SqlSessionFactory的注入的。因为SqlSessionTemplate的创建也是需要注入SqlSessionFactory的。
二.实现代码
1.继承SqlSessionTemplate 重写getSqlSessionFactory,getConfiguration和SqlSessionInterceptor
001 | package com.hoo.framework.mybatis.support; |
003 | import static java.lang.reflect.Proxy.newProxyInstance; |
004 | import static org.apache.ibatis.reflection.ExceptionUtil.unwrapThrowable; |
005 | import static org.mybatis.spring.SqlSessionUtils.closeSqlSession; |
006 | import static org.mybatis.spring.SqlSessionUtils.getSqlSession; |
007 | import static org.mybatis.spring.SqlSessionUtils.isSqlSessionTransactional; |
009 | import java.lang.reflect.InvocationHandler; |
010 | import java.lang.reflect.Method; |
011 | import java.sql.Connection; |
012 | import java.util.List; |
015 | import org.apache.ibatis.exceptions.PersistenceException; |
016 | import org.apache.ibatis.executor.BatchResult; |
017 | import org.apache.ibatis.session.Configuration; |
018 | import org.apache.ibatis.session.ExecutorType; |
019 | import org.apache.ibatis.session.ResultHandler; |
020 | import org.apache.ibatis.session.RowBounds; |
021 | import org.apache.ibatis.session.SqlSession; |
022 | import org.apache.ibatis.session.SqlSessionFactory; |
023 | import org.mybatis.spring.MyBatisExceptionTranslator; |
024 | import org.mybatis.spring.SqlSessionTemplate; |
025 | import org.springframework.dao.support.PersistenceExceptionTranslator; |
026 | import org.springframework.util.Assert; |
029 | * <b>function:</b> 继承SqlSessionTemplate 重写相关方法 |
031 | * @createDate 2013-10-18 下午03:07:46 |
032 | * @file CustomSqlSessionTemplate.java |
033 | * @package com.hoo.framework.mybatis.support |
036 | * @email hoojo_@126.com |
039 | public class CustomSqlSessionTemplate extends SqlSessionTemplate { |
041 | private final SqlSessionFactory sqlSessionFactory; |
042 | private final ExecutorType executorType; |
043 | private final SqlSession sqlSessionProxy; |
044 | private final PersistenceExceptionTranslator exceptionTranslator; |
046 | private Map<Object, SqlSessionFactory> targetSqlSessionFactorys; |
047 | private SqlSessionFactory defaultTargetSqlSessionFactory; |
049 | public void setTargetSqlSessionFactorys(Map<Object, SqlSessionFactory> targetSqlSessionFactorys) { |
050 | this .targetSqlSessionFactorys = targetSqlSessionFactorys; |
053 | public void setDefaultTargetSqlSessionFactory(SqlSessionFactory defaultTargetSqlSessionFactory) { |
054 | this .defaultTargetSqlSessionFactory = defaultTargetSqlSessionFactory; |
057 | public CustomSqlSessionTemplate(SqlSessionFactory sqlSessionFactory) { |
058 | this (sqlSessionFactory, sqlSessionFactory.getConfiguration().getDefaultExecutorType()); |
061 | public CustomSqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType) { |
062 | this (sqlSessionFactory, executorType, new MyBatisExceptionTranslator(sqlSessionFactory.getConfiguration() |
063 | .getEnvironment().getDataSource(), true )); |
066 | public CustomSqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType, |
067 | PersistenceExceptionTranslator exceptionTranslator) { |
069 | super (sqlSessionFactory, executorType, exceptionTranslator); |
071 | this .sqlSessionFactory = sqlSessionFactory; |
072 | this .executorType = executorType; |
073 | this .exceptionTranslator = exceptionTranslator; |
075 | this .sqlSessionProxy = (SqlSession) newProxyInstance( |
076 | SqlSessionFactory. class .getClassLoader(), |
077 | new Class[] { SqlSession. class }, |
078 | new SqlSessionInterceptor()); |
080 | this .defaultTargetSqlSessionFactory = sqlSessionFactory; |
084 | public SqlSessionFactory getSqlSessionFactory() { |
086 | SqlSessionFactory targetSqlSessionFactory = targetSqlSessionFactorys.get(CustomerContextHolder.getContextType()); |
087 | if (targetSqlSessionFactory != null ) { |
088 | return targetSqlSessionFactory; |
089 | } else if (defaultTargetSqlSessionFactory != null ) { |
090 | return defaultTargetSqlSessionFactory; |
092 | Assert.notNull(targetSqlSessionFactorys, "Property 'targetSqlSessionFactorys' or 'defaultTargetSqlSessionFactory' are required" ); |
093 | Assert.notNull(defaultTargetSqlSessionFactory, "Property 'defaultTargetSqlSessionFactory' or 'targetSqlSessionFactorys' are required" ); |
095 | return this .sqlSessionFactory; |
099 | public Configuration getConfiguration() { |
100 | return this .getSqlSessionFactory().getConfiguration(); |
103 | public ExecutorType getExecutorType() { |
104 | return this .executorType; |
107 | public PersistenceExceptionTranslator getPersistenceExceptionTranslator() { |
108 | return this .exceptionTranslator; |
114 | public <T> T selectOne(String statement) { |
115 | return this .sqlSessionProxy.<T> selectOne(statement); |
121 | public <T> T selectOne(String statement, Object parameter) { |
122 | return this .sqlSessionProxy.<T> selectOne(statement, parameter); |
128 | public <K, V> Map<K, V> selectMap(String statement, String mapKey) { |
129 | return this .sqlSessionProxy.<K, V> selectMap(statement, mapKey); |
135 | public <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey) { |
136 | return this .sqlSessionProxy.<K, V> selectMap(statement, parameter, mapKey); |
142 | public <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey, RowBounds rowBounds) { |
143 | return this .sqlSessionProxy.<K, V> selectMap(statement, parameter, mapKey, rowBounds); |
149 | public <E> List<E> selectList(String statement) { |
150 | return this .sqlSessionProxy.<E> selectList(statement); |
156 | public <E> List<E> selectList(String statement, Object parameter) { |
157 | return this .sqlSessionProxy.<E> selectList(statement, parameter); |
163 | public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) { |
164 | return this .sqlSessionProxy.<E> selectList(statement, parameter, rowBounds); |
170 | public void select(String statement, ResultHandler handler) { |
171 | this .sqlSessionProxy.select(statement, handler); |
177 | public void select(String statement, Object parameter, ResultHandler handler) { |
178 | this .sqlSessionProxy.select(statement, parameter, handler); |
184 | public void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) { |
185 | this .sqlSessionProxy.select(statement, parameter, rowBounds, handler); |
191 | public int insert(String statement) { |
192 | return this .sqlSessionProxy.insert(statement); |
198 | public int insert(String statement, Object parameter) { |
199 | return this .sqlSessionProxy.insert(statement, parameter); |
205 | public int update(String statement) { |
206 | return this .sqlSessionProxy.update(statement); |
212 | public int update(String statement, Object parameter) { |
213 | return this .sqlSessionProxy.update(statement, parameter); |
219 | public int delete(String statement) { |
220 | return this .sqlSessionProxy.delete(statement); |
226 | public int delete(String statement, Object parameter) { |
227 | return this .sqlSessionProxy.delete(statement, parameter); |
233 | public <T> T getMapper(Class<T> type) { |
234 | return getConfiguration().getMapper(type, this ); |
240 | public void commit() { |
241 | throw new UnsupportedOperationException( "Manual commit is not allowed over a Spring managed SqlSession" ); |
247 | public void commit( boolean force) { |
248 | throw new UnsupportedOperationException( "Manual commit is not allowed over a Spring managed SqlSession" ); |
254 | public void rollback() { |
255 | throw new UnsupportedOperationException( "Manual rollback is not allowed over a Spring managed SqlSession" ); |
261 | public void rollback( boolean force) { |
262 | throw new UnsupportedOperationException( "Manual rollback is not allowed over a Spring managed SqlSession" ); |
268 | public void close() { |
269 | throw new UnsupportedOperationException( "Manual close is not allowed over a Spring managed SqlSession" ); |
275 | public void clearCache() { |
276 | this .sqlSessionProxy.clearCache(); |
282 | public Connection getConnection() { |
283 | return this .sqlSessionProxy.getConnection(); |
290 | public List<BatchResult> flushStatements() { |
291 | return this .sqlSessionProxy.flushStatements(); |
295 | * Proxy needed to route MyBatis method calls to the proper SqlSession got from Spring's Transaction Manager It also |
296 | * unwraps exceptions thrown by {@code Method#invoke(Object, Object...)} to pass a {@code PersistenceException} to |
297 | * the {@code PersistenceExceptionTranslator}. |
299 | private class SqlSessionInterceptor implements InvocationHandler { |
300 | public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { |
301 | final SqlSession sqlSession = getSqlSession( |
302 | CustomSqlSessionTemplate. this .getSqlSessionFactory(), |
303 | CustomSqlSessionTemplate. this .executorType, |
304 | CustomSqlSessionTemplate. this .exceptionTranslator); |
306 | Object result = method.invoke(sqlSession, args); |
307 | if (!isSqlSessionTransactional(sqlSession, CustomSqlSessionTemplate. this .getSqlSessionFactory())) { |
310 | sqlSession.commit( true ); |
313 | } catch (Throwable t) { |
314 | Throwable unwrapped = unwrapThrowable(t); |
315 | if (CustomSqlSessionTemplate. this .exceptionTranslator != null && unwrapped instanceof PersistenceException) { |
316 | Throwable translated = CustomSqlSessionTemplate. this .exceptionTranslator |
317 | .translateExceptionIfPossible((PersistenceException) unwrapped); |
318 | if (translated != null ) { |
319 | unwrapped = translated; |
324 | closeSqlSession(sqlSession, CustomSqlSessionTemplate. this .getSqlSessionFactory()); |
重写后的getSqlSessionFactory方法会从我们配置的SqlSessionFactory集合targetSqlSessionFactorys或默认的defaultTargetSqlSessionFactory中获取Session对象。而改写的SqlSessionInterceptor 是这个MyBatis整合Spring的关键,所有的SqlSessionFactory对象的session都将在这里完成创建、提交、关闭等操作。所以我们改写这里的代码,在这里获取getSqlSessionFactory的时候,从多个SqlSessionFactory中获取我们设置的那个即可。
上面添加了targetSqlSessionFactorys、defaultTargetSqlSessionFactory两个属性来配置多个SqlSessionFactory对象和默认的SqlSessionFactory对象。
CustomerContextHolder 设置SqlSessionFactory的类型
01 | package com.hoo.framework.mybatis.support; |
06 | public abstract class CustomerContextHolder { |
08 | public final static String SESSION_FACTORY_MYSQL = "mysql" ; |
09 | public final static String SESSION_FACTORY_ORACLE = "oracle" ; |
11 | private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>(); |
13 | public static void setContextType(String contextType) { |
14 | contextHolder.set(contextType); |
17 | public static String getContextType() { |
18 | return contextHolder.get(); |
21 | public static void clearContextType() { |
22 | contextHolder.remove(); |
2、配置相关的文件applicationContext-session-factory.xml
001 | <?xml version= "1.0" encoding= "UTF-8" ?> |
006 | xsi:schemaLocation="http: |
014 | <bean id= "dataSourceOracle" class = "com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method= "close" > |
015 | <property name= "driverClass" value= "${datasource.driver}" /> |
016 | <property name= "jdbcUrl" value= "${datasource.url}" /> |
017 | <property name= "user" value= "${datasource.username}" /> |
018 | <property name= "password" value= "${datasource.password}" /> |
020 | <property name= "acquireIncrement" value= "${c3p0.acquireIncrement}" /> |
021 | <property name= "initialPoolSize" value= "${c3p0.initialPoolSize}" /> |
022 | <property name= "minPoolSize" value= "${c3p0.minPoolSize}" /> |
023 | <property name= "maxPoolSize" value= "${c3p0.maxPoolSize}" /> |
024 | <property name= "maxIdleTime" value= "${c3p0.maxIdleTime}" /> |
025 | <property name= "idleConnectionTestPeriod" value= "${c3p0.idleConnectionTestPeriod}" /> |
026 | <property name= "maxStatements" value= "${c3p0.maxStatements}" /> |
027 | <property name= "numHelperThreads" value= "${c3p0.numHelperThreads}" /> |
028 | <property name= "preferredTestQuery" value= "${c3p0.preferredTestQuery}" /> |
029 | <property name= "testConnectionOnCheckout" value= "${c3p0.testConnectionOnCheckout}" /> |
032 | <bean id= "dataSourceMySQL" class = "com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method= "close" > |
033 | <property name= "driverClass" value= "com.mysql.jdbc.Driver" /> |
035 | <property name= "user" value= "root" /> |
036 | <property name= "password" value= "jp2011" /> |
038 | <property name= "acquireIncrement" value= "${c3p0.acquireIncrement}" /> |
039 | <property name= "initialPoolSize" value= "${c3p0.initialPoolSize}" /> |
040 | <property name= "minPoolSize" value= "${c3p0.minPoolSize}" /> |
041 | <property name= "maxPoolSize" value= "${c3p0.maxPoolSize}" /> |
042 | <property name= "maxIdleTime" value= "${c3p0.maxIdleTime}" /> |
043 | <property name= "idleConnectionTestPeriod" value= "${c3p0.idleConnectionTestPeriod}" /> |
044 | <property name= "maxStatements" value= "${c3p0.maxStatements}" /> |
045 | <property name= "numHelperThreads" value= "${c3p0.numHelperThreads}" /> |
046 | <property name= "preferredTestQuery" value= "${c3p0.preferredTestQuery}" /> |
047 | <property name= "testConnectionOnCheckout" value= "${c3p0.testConnectionOnCheckout}" /> |
050 | <!-- 配置SqlSessionFactoryBean --> |
051 | <bean id= "oracleSqlSessionFactory" class = "org.mybatis.spring.SqlSessionFactoryBean" > |
052 | <property name= "dataSource" ref= "dataSourceOracle" /> |
053 | <property name= "configLocation" value= "classpath:mybatis.xml" /> |
054 | <!-- mapper和resultmap配置路径 --> |
055 | <property name= "mapperLocations" > |
057 | <!-- 表示在com.hoo目录下的任意包下的resultmap包目录中,以-resultmap.xml或-mapper.xml结尾所有文件 --> |
058 | <value>classpath:com/hoo/framework/mybatis/mybatis-common.xml</value> |
059 | <value>classpath:com/hoo resultmap |
078 | multiple-datasource-mapper.xml</value> |
083 | <!-- 配置自定义的SqlSessionTemplate模板,注入相关配置 --> |
084 | <bean id= "sqlSessionTemplate" class = "com.hoo.framework.mybatis.support.CustomSqlSessionTemplate" > |
085 | <constructor-arg ref= "oracleSqlSessionFactory" /> |
086 | <property name= "targetSqlSessionFactorys" > |
088 | <entry value-ref= "oracleSqlSessionFactory" key= "oracle" /> |
089 | <entry value-ref= "mysqlSqlSessionFactory" key= "mysql" /> |
094 | <!-- 通过扫描的模式,扫描目录在com/hoo/任意目录下的mapper目录下,所有的mapper都需要继承SqlMapper接口的接口 --> |
095 | <bean class = "org.mybatis.spring.mapper.MapperScannerConfigurer" > |
096 | <property name= "basePackage" value= "com.hoo.**.mapper" /> |
097 | <!-- 注意注入sqlSessionTemplate --> |
098 | <property name= "sqlSessionTemplateBeanName" value= "sqlSessionTemplate" /> |
099 | <property name= "markerInterface" value= "com.hoo.framework.mybatis.SqlMapper" /> |
上面的配置关键是在MapperScannerConfigurer中注入sqlSessionTemplate,这个要注意。当我们配置了多个SqlSessionFactoryBean的时候,就需要为MapperScannerConfigurer指定一个sqlSessionFactoryBeanName或是sqlSessionTemplateBeanName。一般情况下注入了sqlSessionTemplateBeanName对象,那sqlSessionFactory也就有值了。如果单独的注入了sqlSessionFactory那么程序会创建一个sqlSessionTemplate对象。我们可以看看代码SqlSessionFactoryDaoSupport对象的代码。如果你不喜欢使用扫描的方式,也可以注入sqlSessionTemplate或继承sqlSessionTemplate完成数据库操作。
01 | public abstract class SqlSessionDaoSupport extends DaoSupport { |
03 | private SqlSession sqlSession; |
05 | private boolean externalSqlSession; |
07 | public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) { |
08 | if (! this .externalSqlSession) { |
09 | this .sqlSession = new SqlSessionTemplate(sqlSessionFactory); |
13 | public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) { |
14 | this .sqlSession = sqlSessionTemplate; |
15 | this .externalSqlSession = true ; |
这段代码很明显,如果注入了sqlSessionTemplate上面的注入也就不会执行了,如果没有注入sqlSessionTemplate,那么会自动new一个sqlSessionTemplate对象。
3、编写相关测试接口和实现的mapper.xml
01 | package com.hoo.server.datasource.mapper; |
05 | import com.hoo.framework.mybatis.SqlMapper; |
09 | public interface MultipleDataSourceMapper extends SqlMapper { |
11 | public List<Map<String, Object>> execute4MySQL() throws Exception; |
13 | public List<Map<String, Object>> execute4Oracle() throws Exception; |
01 | multiple-datasource-mapper.xml |
04 | <? xml version = "1.0" encoding = "UTF-8" ?> |
06 | < mapper namespace = "com.hoo.server.datasource.mapper.MultipleDataSourceMapper" > |
08 | < select id = "execute4Oracle" resultType = "map" > |
13 | deviceInfo_tab t where rownum < 10 |
17 | < select id = "execute4MySQL" resultType = "map" > |
上面分别查询oracle和mysql两个数据库中的table
4、测试代码
02 | @Qualifier ( "multipleDataSourceMapper" ) |
03 | private MultipleDataSourceMapper mapper; |
06 | public void testMapper() { |
07 | CustomerContextHolder.setContextType(CustomerContextHolder.SESSION_FACTORY_MYSQL); |
09 | trace(mapper.execute4MySQL()); |
10 | } catch (Exception e1) { |
13 | CustomerContextHolder.setContextType(CustomerContextHolder.SESSION_FACTORY_ORACLE); |
15 | trace(mapper.execute4Oracle()); |
16 | } catch (Exception e) { |
运行后发现能够顺利查询出数据。
如果你是重写SqlSessionDaoSupport,那么方法如下
01 | package com.hoo.framework.mybatis.support; |
04 | import org.apache.ibatis.session.SqlSession; |
05 | import org.apache.ibatis.session.SqlSessionFactory; |
06 | import org.mybatis.spring.SqlSessionUtils; |
07 | import org.mybatis.spring.support.SqlSessionDaoSupport; |
08 | import org.springframework.beans.BeansException; |
09 | import org.springframework.context.ApplicationContext; |
10 | import org.springframework.context.ApplicationContextAware; |
14 | public class DynamicSqlSessionDaoSupport extends SqlSessionDaoSupport implements ApplicationContextAware { |
16 | private ApplicationContext applicationContext; |
18 | private Map<Object, SqlSessionFactory> targetSqlSessionFactorys; |
19 | private SqlSessionFactory defaultTargetSqlSessionFactory; |
20 | private SqlSession sqlSession; |
23 | public final SqlSession getSqlSession() { |
24 | SqlSessionFactory targetSqlSessionFactory = targetSqlSessionFactorys.get(CustomerContextHolder.getContextType()); |
25 | if (targetSqlSessionFactory != null ) { |
26 | setSqlSessionFactory(targetSqlSessionFactory); |
27 | } else if (defaultTargetSqlSessionFactory != null ) { |
28 | setSqlSessionFactory(defaultTargetSqlSessionFactory); |
29 | targetSqlSessionFactory = defaultTargetSqlSessionFactory; |
31 | targetSqlSessionFactory = (SqlSessionFactory) applicationContext.getBean(CustomerContextHolder.getContextType()); |
32 | setSqlSessionFactory(targetSqlSessionFactory); |
34 | this .sqlSession = SqlSessionUtils.getSqlSession(targetSqlSessionFactory); |
35 | return this .sqlSession; |
39 | protected void checkDaoConfig() { |
43 | public void setTargetSqlSessionFactorys(Map<Object, SqlSessionFactory> targetSqlSessionFactorys) { |
44 | this .targetSqlSessionFactorys = targetSqlSessionFactorys; |
47 | public void setDefaultTargetSqlSessionFactory(SqlSessionFactory defaultTargetSqlSessionFactory) { |
48 | this .defaultTargetSqlSessionFactory = defaultTargetSqlSessionFactory; |
52 | public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { |
53 | this .applicationContext = applicationContext; |
主要重写getSqlSession方法,上面获取SqlSessionFactory的方法。
重写好了后就可以配置这个对象,配置代码如下
//每一个DAO由继承SqlSessionDaoSupport全部改为DynamicSqlSessionDaoSupport
1 | public class UserMapperDaoImpl extends DynamicSqlSessionDaoSupport implements UserDao { |
3 | public int addUser(User user) { |
4 | return this .getSqlSession().insert( "com.hoo.user.dao.UserDao.addUser" , user); |
在上面的配置文件中加入配置
01 | < bean id = "baseDao" class = "com.hoo.framework.mybatis.support.DynamicSqlSessionDaoSupport" abstract = "true" lazy-init = "true" > |
02 | < property name = "targetSqlSessionFactorys" > |
04 | < entry value-ref = "oracleSqlSessionFactory" key = "oracle" /> |
05 | < entry value-ref = "mysqlSqlSessionFactory" key = "mysql" /> |
08 | < property name = "defaultTargetSqlSessionFactory" ref = "oracleSqlSessionFactory" /> |
11 | < bean id = "userMapperDao" class = "com.hoo.user.dao.impl.UserMapperDaoImpl" parent = "baseDao" /> |
就这样也可以利用DynamicSqlSessionDaoSupport来完成动态切换sqlSessionFactory对象,只需用在注入userMapperDao调用方法的时候设置下CustomerContextHolder的contextType即可。
三.总结
为了实现这个功能看了mybatis-spring-1.2.0.jar这个包的部分源代码,代码内容不是很多。所以看了下主要的代码,下面做些简单的介绍。
MapperScannerConfigurer这个类就是我们要扫描的Mapper接口的类,也就是basePackage中继承markerInterface配置的接口。可以看看ClassPathBeanDefinitionScanner、ClassPathMapperScanner中的doScan这个方法。它会扫描basePackage这个包下所有接口,在ClassPathScanningCandidateComponentProvider中有这个方法findCandidateComponents,它会找到所有的BeanDefinition。
最重要的一点是ClassPathMapperScanner中的doScan这个方法它会给这些接口创建一个MapperFactoryBean。并且会检查sqlSessionFactory和sqlSessionTemplate对象的注入情况。

所以我们配置扫描的方式也就相当于我们在配置文件中给每一个Mapper配置一个MapperFactoryBean一样。而这个MapperFactoryBean又继承SqlSessionDaoSupport。所以当初我想重写MapperScannerConfigurer中的postProcessBeanDefinitionRegistry方法,然后重写方法中的ClassPathMapperScanner中的doScan方法,将definition.setBeanClass(MapperFactoryBean.class);改成自己定义的MapperFactoryBean。最后以失败告终,因为这里是Spring装载扫描对象的时候都已经为这些对象创建好了代理、设置好了mapperInterface和注入需要的类。所以在调用相关操作数据库的API方法的时候,设置对应的SqlSessionFactory也是无效的。
辗转反侧我看到了SqlSessionTemplate这个类,它的功能相当于SqlSessionDaoSupport的实现类MapperFactoryBean。最为关键的是SqlSessionTemplate有一个拦截器SqlSessionInterceptor,它复制所有SqlSession的创建、提交、关闭,而且是在每个方法之前。这点在上面也提到过了!所以我们只需要在SqlSessionInterceptor方法中获取SqlSessionFactory的时候,在这之前调用下CustomerContextHolder.setContextType方法即可完成数据库的SqlSessionFactory的切换。而在MapperScannerConfigurer提供了注入SqlSessionFactory和sqlSessionTemplate的方法,如果注入了SqlSessionFactory系统将会new一个sqlSessionTemplate,而注入了sqlSessionTemplate就不会创建其他对象(见下面代码)。所以我们配置一个sqlSessionTemplate并注入到MapperScannerConfigurer中,程序将会使用这个sqlSessionTemplate。本文最后的实现方式就是这样完成的。
01 | public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) { |
02 | if (! this .externalSqlSession) { |
03 | this .sqlSession = new SqlSessionTemplate(sqlSessionFactory); |
07 | public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) { |
08 | this .sqlSession = sqlSessionTemplate; |
09 | this .externalSqlSession = true ; |
原文地址:http://www.blogjava.net/hoojo/archive/2013/10/22/405488.html
欢迎拜访!
由
最代码官方编辑于2016-7-9 18:10:58