作者:hoojo
出处: http://www.blogjava.net/hoojo/archive/2013/10/22/405488.html
blog:http://blog.csdn.net/IBM_hoojo
http://hoojo.cnblogs.com
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
一、摘要
上两篇文章分别介绍了Spring3.3 整合 Hibernate3、MyBatis3.2 配置多数据源/动态切换数据源 方法 和 Spring3 整合Hibernate3.5 动态切换SessionFactory (切换数据库方言),这篇文章将介绍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
package com.hoo.framework.mybatis.support;
import static java.lang.reflect.Proxy.newProxyInstance;import static org.apache.ibatis.reflection.ExceptionUtil.unwrapThrowable;import static org.mybatis.spring.SqlSessionUtils.closeSqlSession;import static org.mybatis.spring.SqlSessionUtils.getSqlSession;import static org.mybatis.spring.SqlSessionUtils.isSqlSessionTransactional;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.util.List;
import java.util.Map;
import org.apache.ibatis.exceptions.PersistenceException;
import org.apache.ibatis.executor.BatchResult;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.MyBatisExceptionTranslator;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.dao.support.PersistenceExceptionTranslator;
import org.springframework.util.Assert;
/**
* <b>function:</b> 继承SqlSessionTemplate 重写相关方法
* @author hoojo
* @createDate 2013-10-18 下午03:07:46
* @file CustomSqlSessionTemplate.java
* @package com.hoo.framework.mybatis.support
* @project SHMB
* @blog http://blog.csdn.net/IBM_hoojo
* @email hoojo_@126.com
* @version 1.0
*/
public class CustomSqlSessionTemplate extends SqlSessionTemplate {private final SqlSessionFactory sqlSessionFactory;private final ExecutorType executorType;private final SqlSession sqlSessionProxy;private final PersistenceExceptionTranslator exceptionTranslator;private Map<Object, SqlSessionFactory> targetSqlSessionFactorys;
private SqlSessionFactory defaultTargetSqlSessionFactory;
public void setTargetSqlSessionFactorys(Map<Object, SqlSessionFactory> targetSqlSessionFactorys) {this.targetSqlSessionFactorys = targetSqlSessionFactorys;
}public void setDefaultTargetSqlSessionFactory(SqlSessionFactory defaultTargetSqlSessionFactory) {this.defaultTargetSqlSessionFactory = defaultTargetSqlSessionFactory;
}public CustomSqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
this(sqlSessionFactory, sqlSessionFactory.getConfiguration().getDefaultExecutorType());
}public CustomSqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType) {
this(sqlSessionFactory, executorType, new MyBatisExceptionTranslator(sqlSessionFactory.getConfiguration().getEnvironment().getDataSource(), true));}public CustomSqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType,
PersistenceExceptionTranslator exceptionTranslator) {super(sqlSessionFactory, executorType, exceptionTranslator);
this.sqlSessionFactory = sqlSessionFactory;
this.executorType = executorType;
this.exceptionTranslator = exceptionTranslator;
this.sqlSessionProxy = (SqlSession) newProxyInstance(
SqlSessionFactory.class.getClassLoader(),
new Class[] { SqlSession.class },new SqlSessionInterceptor());
this.defaultTargetSqlSessionFactory = sqlSessionFactory;
}@Overridepublic SqlSessionFactory getSqlSessionFactory() {
SqlSessionFactory targetSqlSessionFactory = targetSqlSessionFactorys.get(CustomerContextHolder.getContextType());if (targetSqlSessionFactory != null) {
return targetSqlSessionFactory;
} else if (defaultTargetSqlSessionFactory != null) {return defaultTargetSqlSessionFactory;
} else {
Assert.notNull(targetSqlSessionFactorys, "Property 'targetSqlSessionFactorys' or 'defaultTargetSqlSessionFactory' are required");
Assert.notNull(defaultTargetSqlSessionFactory, "Property 'defaultTargetSqlSessionFactory' or 'targetSqlSessionFactorys' are required");
}return this.sqlSessionFactory;}@Overridepublic Configuration getConfiguration() {
return this.getSqlSessionFactory().getConfiguration();}public ExecutorType getExecutorType() {
return this.executorType;}public PersistenceExceptionTranslator getPersistenceExceptionTranslator() {
return this.exceptionTranslator;}/**
* {@inheritDoc}
*/
public <T> T selectOne(String statement) {
return this.sqlSessionProxy.<T> selectOne(statement);}/**
* {@inheritDoc}
*/
public <T> T selectOne(String statement, Object parameter) {
return this.sqlSessionProxy.<T> selectOne(statement, parameter);}/**
* {@inheritDoc}
*/
public <K, V> Map<K, V> selectMap(String statement, String mapKey) {
return this.sqlSessionProxy.<K, V> selectMap(statement, mapKey);}/**
* {@inheritDoc}
*/
public <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey) {
return this.sqlSessionProxy.<K, V> selectMap(statement, parameter, mapKey);}/**
* {@inheritDoc}
*/
public <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey, RowBounds rowBounds) {
return this.sqlSessionProxy.<K, V> selectMap(statement, parameter, mapKey, rowBounds);}/**
* {@inheritDoc}
*/
public <E> List<E> selectList(String statement) {
return this.sqlSessionProxy.<E> selectList(statement);}/**
* {@inheritDoc}
*/
public <E> List<E> selectList(String statement, Object parameter) {
return this.sqlSessionProxy.<E> selectList(statement, parameter);}/**
* {@inheritDoc}
*/
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
return this.sqlSessionProxy.<E> selectList(statement, parameter, rowBounds);}/**
* {@inheritDoc}
*/
public void select(String statement, ResultHandler handler) {this.sqlSessionProxy.select(statement, handler);
}/**
* {@inheritDoc}
*/
public void select(String statement, Object parameter, ResultHandler handler) {this.sqlSessionProxy.select(statement, parameter, handler);
}/**
* {@inheritDoc}
*/
public void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) {this.sqlSessionProxy.select(statement, parameter, rowBounds, handler);
}/**
* {@inheritDoc}
*/
public int insert(String statement) {return this.sqlSessionProxy.insert(statement);}/**
* {@inheritDoc}
*/
public int insert(String statement, Object parameter) {return this.sqlSessionProxy.insert(statement, parameter);}/**
* {@inheritDoc}
*/
public int update(String statement) {return this.sqlSessionProxy.update(statement);}/**
* {@inheritDoc}
*/
public int update(String statement, Object parameter) {return this.sqlSessionProxy.update(statement, parameter);}/**
* {@inheritDoc}
*/
public int delete(String statement) {return this.sqlSessionProxy.delete(statement);}/**
* {@inheritDoc}
*/
public int delete(String statement, Object parameter) {return this.sqlSessionProxy.delete(statement, parameter);}/**
* {@inheritDoc}
*/
public <T> T getMapper(Class<T> type) {
return getConfiguration().getMapper(type, this);}/**
* {@inheritDoc}
*/
public void commit() {throw new UnsupportedOperationException("Manual commit is not allowed over a Spring managed SqlSession");}/**
* {@inheritDoc}
*/
public void commit(boolean force) {throw new UnsupportedOperationException("Manual commit is not allowed over a Spring managed SqlSession");}/**
* {@inheritDoc}
*/
public void rollback() {throw new UnsupportedOperationException("Manual rollback is not allowed over a Spring managed SqlSession");}/**
* {@inheritDoc}
*/
public void rollback(boolean force) {throw new UnsupportedOperationException("Manual rollback is not allowed over a Spring managed SqlSession");}/**
* {@inheritDoc}
*/
public void close() {throw new UnsupportedOperationException("Manual close is not allowed over a Spring managed SqlSession");}/**
* {@inheritDoc}
*/
public void clearCache() {this.sqlSessionProxy.clearCache();
}/**
* {@inheritDoc}
*/
public Connection getConnection() {
return this.sqlSessionProxy.getConnection();}/**
* {@inheritDoc}
* @since 1.0.2
*/
public List<BatchResult> flushStatements() {
return this.sqlSessionProxy.flushStatements();}/**
* Proxy needed to route MyBatis method calls to the proper SqlSession got from Spring's Transaction Manager It also
* unwraps exceptions thrown by {@code Method#invoke(Object, Object...)} to pass a {@code PersistenceException} to
* the {@code PersistenceExceptionTranslator}.
*/
private class SqlSessionInterceptor implements InvocationHandler {public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {final SqlSession sqlSession = getSqlSession(
CustomSqlSessionTemplate.this.getSqlSessionFactory(),
CustomSqlSessionTemplate.this.executorType,
CustomSqlSessionTemplate.this.exceptionTranslator);
try {
Object result = method.invoke(sqlSession, args);if (!isSqlSessionTransactional(sqlSession, CustomSqlSessionTemplate.this.getSqlSessionFactory())) {// force commit even on non-dirty sessions because some databases require
// a commit/rollback before calling close()
sqlSession.commit(true);}return result;
} catch (Throwable t) {
Throwable unwrapped = unwrapThrowable(t);if (CustomSqlSessionTemplate.this.exceptionTranslator != null && unwrapped instanceof PersistenceException) {Throwable translated = CustomSqlSessionTemplate.this.exceptionTranslator
.translateExceptionIfPossible((PersistenceException) unwrapped);if (translated != null) {
unwrapped = translated;}}throw unwrapped;
} finally {
closeSqlSession(sqlSession, CustomSqlSessionTemplate.this.getSqlSessionFactory());
}}}}
重写后的getSqlSessionFactory方法会从我们配置的SqlSessionFactory集合targetSqlSessionFactorys或默认的defaultTargetSqlSessionFactory中获取Session对象。而 改写的SqlSessionInterceptor 是这个MyBatis整合Spring的关键,所有的SqlSessionFactory对象的session都将在这里完成创建、提交、关闭等操作。所 以我们改写这里的代码,在这里获取getSqlSessionFactory的时候,从多个SqlSessionFactory中获取我们设置的那个即 可。
上面添加了targetSqlSessionFactorys、defaultTargetSqlSessionFactory两个属性来配置多个SqlSessionFactory对象和默认的SqlSessionFactory对象。
CustomerContextHolder 设置SqlSessionFactory的类型
package com.hoo.framework.mybatis.support;
/**
* <b>function:</b> 多数据源
* @author hoojo
* @createDate 2013-9-27 上午11:36:57
* @file CustomerContextHolder.java
* @package com.hoo.framework.spring.support
* @project SHMB
* @blog http://blog.csdn.net/IBM_hoojo
* @email hoojo_@126.com
* @version 1.0
*/
public abstract class CustomerContextHolder {public final static String SESSION_FACTORY_MYSQL = "mysql";public final static String SESSION_FACTORY_ORACLE = "oracle";private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();public static void setContextType(String contextType) {contextHolder.set(contextType);}public static String getContextType() {return contextHolder.get();
}public static void clearContextType() {contextHolder.remove();}}
2、配置相关的文件applicationContext-session-factory.xml
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"xmlns:aop="http://www.springframework.org/schema/aop"xmlns:tx="http://www.springframework.org/schema/tx"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-3.2.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop-3.2.xsdhttp://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx-3.2.xsd ">
<!-- 配置c3p0数据源 -->
<bean id="dataSourceOracle" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"><property name="driverClass" value="${datasource.driver}"/><property name="jdbcUrl" value="${datasource.url}"/><property name="user" value="${datasource.username}"/><property name="password" value="${datasource.password}"/><property name="acquireIncrement" value="${c3p0.acquireIncrement}"/><property name="initialPoolSize" value="${c3p0.initialPoolSize}"/><property name="minPoolSize" value="${c3p0.minPoolSize}"/><property name="maxPoolSize" value="${c3p0.maxPoolSize}"/><property name="maxIdleTime" value="${c3p0.maxIdleTime}"/><property name="idleConnectionTestPeriod" value="${c3p0.idleConnectionTestPeriod}"/><property name="maxStatements" value="${c3p0.maxStatements}"/><property name="numHelperThreads" value="${c3p0.numHelperThreads}"/><property name="preferredTestQuery" value="${c3p0.preferredTestQuery}"/><property name="testConnectionOnCheckout" value="${c3p0.testConnectionOnCheckout}"/></bean><bean id="dataSourceMySQL" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"><property name="driverClass" value="com.mysql.jdbc.Driver"/><property name="jdbcUrl" value="jdbc:mysql://172.31.108.178:3306/world?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull"/><property name="user" value="root"/><property name="password" value="jp2011"/><property name="acquireIncrement" value="${c3p0.acquireIncrement}"/><property name="initialPoolSize" value="${c3p0.initialPoolSize}"/><property name="minPoolSize" value="${c3p0.minPoolSize}"/><property name="maxPoolSize" value="${c3p0.maxPoolSize}"/><property name="maxIdleTime" value="${c3p0.maxIdleTime}"/><property name="idleConnectionTestPeriod" value="${c3p0.idleConnectionTestPeriod}"/><property name="maxStatements" value="${c3p0.maxStatements}"/><property name="numHelperThreads" value="${c3p0.numHelperThreads}"/><property name="preferredTestQuery" value="${c3p0.preferredTestQuery}"/><property name="testConnectionOnCheckout" value="${c3p0.testConnectionOnCheckout}"/></bean><!-- 配置SqlSessionFactoryBean -->
<bean id="oracleSqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"><property name="dataSource" ref="dataSourceOracle"/><property name="configLocation" value="classpath:mybatis.xml"/><!-- mapper和resultmap配置路径 -->
<property name="mapperLocations"><list><!-- 表示在com.hoo目录下的任意包下的resultmap包目录中,以-resultmap.xml或-mapper.xml结尾所有文件 -->
<value>classpath:com/hoo/framework/mybatis/mybatis-common.xml</value><value>classpath:com/hoo/**/resultmap/*-resultmap.xml</value><value>classpath:com/hoo/**/mapper/*-mapper.xml</value><value>classpath:com/hoo/**/mapper/**/*-mapper.xml</value></list></property></bean><!-- 配置SqlSessionFactoryBean -->
<bean id="mysqlSqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"><property name="dataSource" ref="dataSourceMySQL"/><property name="configLocation" value="classpath:mybatis.xml"/><!-- mapper和resultmap配置路径 -->
<property name="mapperLocations"><list><!-- 表示在com.hoo目录下的任意包下的resultmap包目录中,以-resultmap.xml或-mapper.xml结尾所有文件 (oracle和mysql扫描的配置和路径不一样,如果是公共的都扫描 这里要区分下,不然就报错 找不到对应的表、视图)-->
<value>classpath:com/hoo/framework/mybatis/mybatis-common.xml</value><value>classpath:com/hoo/**/resultmap/*-mysql-resultmap.xml</value><value>classpath:com/hoo/**/mapper/*-mysql-mapper.xml</value><value>classpath:com/hoo/**/mapper/**/*-mysql-mapper.xml</value><value>classpath:com/hoo/**/mapper/**/multiple-datasource-mapper.xml</value></list></property></bean><!-- 配置自定义的SqlSessionTemplate模板,注入相关配置 -->
<bean id="sqlSessionTemplate" class="com.hoo.framework.mybatis.support.CustomSqlSessionTemplate"><constructor-arg ref="oracleSqlSessionFactory" /><property name="targetSqlSessionFactorys"><map><entry value-ref="oracleSqlSessionFactory" key="oracle"/><entry value-ref="mysqlSqlSessionFactory" key="mysql"/></map></property></bean><!-- 通过扫描的模式,扫描目录在com/hoo/任意目录下的mapper目录下,所有的mapper都需要继承SqlMapper接口的接口 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"><property name="basePackage" value="com.hoo.**.mapper"/><!-- 注意注入sqlSessionTemplate -->
<property name="sqlSessionTemplateBeanName" value="sqlSessionTemplate"/><property name="markerInterface" value="com.hoo.framework.mybatis.SqlMapper"/></bean></beans>
上面的配置关键是在MapperScannerConfigurer中注入sqlSessionTemplate,这个要注意。当我们配置了多个 SqlSessionFactoryBean的时候,就需要为MapperScannerConfigurer指定一个 sqlSessionFactoryBeanName或是sqlSessionTemplateBeanName。一般情况下注入了 sqlSessionTemplateBeanName对象,那sqlSessionFactory也就有值了。如果单独的注入了 sqlSessionFactory那么程序会创建一个sqlSessionTemplate对象。我们可以看看代码 SqlSessionFactoryDaoSupport对象的代码。如果你不喜欢使用扫描的方式,也可以注入sqlSessionTemplate或继 承sqlSessionTemplate完成数据库操作。
public abstract class SqlSessionDaoSupport extends DaoSupport {private SqlSession sqlSession;private boolean externalSqlSession;public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {if (!this.externalSqlSession) {this.sqlSession = new SqlSessionTemplate(sqlSessionFactory);}}public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) {this.sqlSession = sqlSessionTemplate;this.externalSqlSession = true;}......
这段代码很明显,如果注入了sqlSessionTemplate上面的注入也就不会执行了。如果没有注入sqlSessionTemplate,那么会自动new一个sqlSessionTemplate对象。
3、编写相关测试接口和实现的mapper.xml
package com.hoo.server.datasource.mapper;
import java.util.List;
import java.util.Map;
import com.hoo.framework.mybatis.SqlMapper;
/**
* <b>function:</b> MyBatis 多数据源 测试查询接口
* @author hoojo
* @createDate 2013-10-10 下午04:18:08
* @file MultipleDataSourceMapper.java
* @package com.hoo.server.datasource.mapper
* @project SHMB
* @blog http://blog.csdn.net/IBM_hoojo
* @email hoojo_@126.com
* @version 1.0
*/
public interface MultipleDataSourceMapper extends SqlMapper {public List<Map<String, Object>> execute4MySQL() throws Exception;public List<Map<String, Object>> execute4Oracle() throws Exception;}
multiple-datasource-mapper.xml
<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.hoo.server.datasource.mapper.MultipleDataSourceMapper"><select id="execute4Oracle" resultType="map"><![CDATA[
SELECT*FROMdeviceInfo_tab t where rownum < 10
]]>
</select><select id="execute4MySQL" resultType="map"><![CDATA[
SELECT*FROMcity limit 2]]>
</select></mapper>
上面分别查询oracle和mysql两个数据库中的table
4、测试代码
@Autowired@Qualifier("multipleDataSourceMapper")
private MultipleDataSourceMapper mapper;
@Testpublic void testMapper() {CustomerContextHolder.setContextType(CustomerContextHolder.SESSION_FACTORY_MYSQL);try {
trace(mapper.execute4MySQL());} catch (Exception e1) {
e1.printStackTrace();}CustomerContextHolder.setContextType(CustomerContextHolder.SESSION_FACTORY_ORACLE);try {
trace(mapper.execute4Oracle());} catch (Exception e) {
e.printStackTrace();}}
运行后发现能够顺利查询出数据。
如果你是重写SqlSessionDaoSupport,那么方法如下
package com.hoo.framework.mybatis.support;
import java.util.Map;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionUtils;
import org.mybatis.spring.support.SqlSessionDaoSupport;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
/**
* <b>function:</b> MyBatis 动态SqlSessionFactory
* @author hoojo
* @createDate 2013-10-14 下午02:32:19
* @file DynamicSqlSessionDaoSupport.java
* @package com.hoo.framework.mybatis.support
* @project SHMB
* @blog http://blog.csdn.net/IBM_hoojo
* @email hoojo_@126.com
* @version 1.0
*/
public class DynamicSqlSessionDaoSupport extends SqlSessionDaoSupport implements ApplicationContextAware {private ApplicationContext applicationContext;
private Map<Object, SqlSessionFactory> targetSqlSessionFactorys;
private SqlSessionFactory defaultTargetSqlSessionFactory;
private SqlSession sqlSession;
@Overridepublic final SqlSession getSqlSession() {SqlSessionFactory targetSqlSessionFactory = targetSqlSessionFactorys.get(CustomerContextHolder.getContextType());if (targetSqlSessionFactory != null) {
setSqlSessionFactory(targetSqlSessionFactory);} else if (defaultTargetSqlSessionFactory != null) {setSqlSessionFactory(defaultTargetSqlSessionFactory);targetSqlSessionFactory = defaultTargetSqlSessionFactory;} else {
targetSqlSessionFactory = (SqlSessionFactory) applicationContext.getBean(CustomerContextHolder.getContextType());setSqlSessionFactory(targetSqlSessionFactory);}this.sqlSession = SqlSessionUtils.getSqlSession(targetSqlSessionFactory);
return this.sqlSession;}@Overrideprotected void checkDaoConfig() {//Assert.notNull(getSqlSession(), "Property 'sqlSessionFactory' or 'sqlSessionTemplate' are required");
}public void setTargetSqlSessionFactorys(Map<Object, SqlSessionFactory> targetSqlSessionFactorys) {this.targetSqlSessionFactorys = targetSqlSessionFactorys;
}public void setDefaultTargetSqlSessionFactory(SqlSessionFactory defaultTargetSqlSessionFactory) {this.defaultTargetSqlSessionFactory = defaultTargetSqlSessionFactory;
}@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.applicationContext = applicationContext;
}}
主要重写getSqlSession方法,上面获取SqlSessionFactory的方法。
重写好了后就可以配置这个对象,配置代码如下
//每一个DAO由继承SqlSessionDaoSupport全部改为DynamicSqlSessionDaoSupport
public class UserMapperDaoImpl extends DynamicSqlSessionDaoSupport implements UserDao {public int addUser(User user) {return this.getSqlSession().insert("com.hoo.user.dao.UserDao.addUser", user);}}在上面的配置文件中加入配置<bean id="baseDao" class="com.hoo.framework.mybatis.support.DynamicSqlSessionDaoSupport" abstract="true" lazy-init="true"><property name="targetSqlSessionFactorys">
<map><entry value-ref="oracleSqlSessionFactory" key="oracle"/><entry value-ref="mysqlSqlSessionFactory" key="mysql"/></map></property><property name="defaultTargetSqlSessionFactory" ref="oracleSqlSessionFactory"/></bean><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。本文最后的实现方式就是这样完成的。
public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {if (!this.externalSqlSession) {this.sqlSession = new SqlSessionTemplate(sqlSessionFactory);}}public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) {this.sqlSession = sqlSessionTemplate;
this.externalSqlSession = true;
}
版权所有,转载请注明出处 本文出自: http://www.blogjava.net/hoojo/archive/2013/10/22/405488.html
相关推荐
Spring3 整合 MyBatis3 配置多数据源动态选择 SqlSessionFactory 详细教程 本教程主要介绍了 Spring3 整合 MyBatis3 配置多数据源动态选择 SqlSessionFactory 的详细教程。下面将详细介绍如何实现 Spring 整合 ...
在SpringBoot项目中,整合Mybatis-Plus并实现多数据源的动态切换,同时支持分页查询是一项常见的需求。以下将详细阐述这个过程中的关键步骤和技术要点。 首先,我们需要引入必要的Maven依赖。这里提到了四个关键...
在提供的"spring整合mybatis多数据源"的demo实例中,你可能能看到上述各个步骤的具体实现,包括配置文件、路由类、以及相关的业务代码。这个实例可以帮助你快速理解并应用到自己的项目中。 总的来说,Spring整合...
本配置示例将详细介绍如何在Spring Boot中整合MyBatis与Oracle数据库,并配置两个不同的数据源。 首先,我们需要理解数据源(DataSource)的概念。数据源是Java应用程序与数据库之间的桥梁,它负责管理数据库连接,...
它们定义了Spring如何管理MyBatis的SqlSessionFactory,以及数据源、事务管理器等核心组件。下面将详细阐述这些配置文件的关键内容。 首先,`User.java`是MyBatis中的Mapper接口,它代表了数据库中的一个表或者一个...
- 配置Mybatis:创建mybatis-config.xml配置文件,定义数据源、事务管理器、SqlSessionFactory等。 - 配置Spring:在Spring的配置文件中,配置SqlSessionFactoryBean、DataSource以及事务管理器,将Mybatis集成到...
- **配置Spring**:创建Spring的配置文件,如`spring-config.xml`,配置数据源、事务管理器以及Mybatis的SqlSessionFactory。 - **配置Mybatis**:创建Mybatis的全局配置文件`mybatis-config.xml`,定义别名、类型...
3. **配置MyBatis**:在MyBatis的配置中,我们将使用Spring管理的数据源,而不是直接创建SqlSessionFactory。在`mybatis-spring`的配置中,我们指定使用Spring的`SqlSessionFactoryBean`,并将数据源设置为我们的...
- **配置文件**: 在application.properties或yaml中设置数据源、Mybatis相关属性。 - **Mapper配置**: 不再需要mybatis-config.xml,而是通过@MapperScan注解扫描Mapper接口。 - **自动配置**: Spring Boot会自动...
以上就是关于"springboot整合mybatis多数据源动态配置 swagger"这一主题的知识点详解,涵盖了Spring Boot与MyBatis的整合、多数据源读写分离的实现,以及Swagger在API文档和测试中的应用。理解并掌握这些内容,对于...
在Spring Boot应用中整合MyBatis并配置Druid数据源以开启SQL监控,是一个常见的数据库管理与优化操作。下面将详细介绍这一过程。 首先,我们需要理解Spring Boot、MyBatis和Druid这三个组件的作用。Spring Boot简化...
在Spring Boot应用中整合MyBatis并配置多数据源是一项常见的任务,这使得应用程序能够根据需求切换或同时处理多个数据库。下面将详细讲解这个过程的关键步骤、涉及的技术点以及注意事项。 1. **Spring Boot与...
在企业级应用开发中,数据源管理是至关重要的部分,特别...通过这个项目,你可以学习到如何在Spring、SpringMVC和Mybatis的环境下实现动态多数据源的配置和管理,这对于大型分布式系统的设计和开发具有很高的实践价值。
- 配置数据源(DataSource),`SqlSessionFactoryBean`将使用该数据源连接数据库。 - 配置`MapperScannerConfigurer`,扫描指定包下的Mapper接口,使Spring能够自动代理这些接口。 2. **Mapper接口与XML配置**: ...
本项目是基于Spring Boot和MyBatis实现的多数据源配置示例,适合在Spring Tool Suite (STS) 开发环境中运行。 首先,我们需要理解Spring Boot的自动配置特性。Spring Boot通过`@EnableAutoConfiguration`注解简化了...
本篇将详细介绍如何在Spring、SpringMVC和MyBatis集成环境中配置多数据源。 首先,我们来理解数据源(DataSource)的概念。数据源是Java中用于存储和管理数据库连接的组件,它实现了Java的javax.sql.DataSource接口...
3. 配置MyBatis:创建MyBatis的配置文件(mybatis-config.xml),定义数据源、事务管理器和Mappers。 4. 编写Mapper接口和SQL映射文件:定义Mapper接口,编写对应的XML映射文件,指定SQL语句和结果映射。 5. 使用...
Spring Boot以其简洁的配置和强大的自动化配置能力,使得集成Mybatis并管理多个数据源变得相对简单。下面我们将详细介绍如何在Spring Boot项目中实现这一配置。 首先,我们需要引入相关的依赖。在`pom.xml`文件中,...
最后,`springMybatis`可能是指项目的根目录或者模块名称,通常包含`src/main/resources`下的Mybatis配置文件、Mapper接口和XML文件,以及`src/main/java`下的业务逻辑和服务层代码。 综上所述,"Spring整合Mybatis...
总结,Spring Boot结合Mybatis和Druid实现多数据源配置的过程包括:配置数据源、配置Mybatis、创建数据源切换器、以及针对不同数据库的测试。这一过程涉及了Spring Boot的自动配置、依赖注入、配置属性绑定等多个...