spring MVC+MyBatis 多数据源配置
2014-11-15 15:48
344 查看
项目框架用的spring MVC和MyBatis,要求有多个数据源,并且数据源能够进行切换,在网上找了好多方法,一种是用在Service上声明事物管理,利用事物进行数据源区分,另一种是利用ThreadLocal来做的,我由于需求,采用第二种方法,首先要重写SqlSessionTemplate这个类,重写后代码如下
这时还需要另一个类来协助切换数据源,也就是ThreadLocal这个办法,需要对其进行设置和获取,该类实现如下:
这两个类准备完毕之后,接下来就是对于框架的数据源进行配置的,你不许有一个默认数据源,所以你必须在你的众多数据源里面设置一个默认数据源,而数据源的配置是我为每个数据源转杯了一个KEY,也就是说我知道KEY就可以随心所欲的切换数据源
applicationContext.xml
package com.sky.scos.common; 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; /** * 类的描述信息 * * @author panzhuowen * @version 1.0.1 */ 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 }, (InvocationHandler) new SqlSessionInterceptor()); this.defaultTargetSqlSessionFactory = sqlSessionFactory; 4000 } @Override public 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; } @Override public 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()); } } } }
这时还需要另一个类来协助切换数据源,也就是ThreadLocal这个办法,需要对其进行设置和获取,该类实现如下:
package com.sky.scos.common; /** * 类的描述信息 * * @author panzhuowen * @version 1.0.1 */ public abstract class CustomerContextHolder { 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(); } }
这两个类准备完毕之后,接下来就是对于框架的数据源进行配置的,你不许有一个默认数据源,所以你必须在你的众多数据源里面设置一个默认数据源,而数据源的配置是我为每个数据源转杯了一个KEY,也就是说我知道KEY就可以随心所欲的切换数据源
public static void setContextType(String contextType) { contextHolder.set(contextType); }通过上面的函数将KEY作为参数传到里面,也就是在和数据源连接时就会走你定义哪个为KEY的数据源,配置文件如下:
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd" default-lazy-init="true"> <description>Spring公共配置</description> <!-- 使用annotation 自动注册bean,并检查@Required,@Autowired的属性已被注入 --> <context:component-scan base-package="com.genghis"> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/> <context:exclude-filter type="annotation" expression="org.springframework.web.bind.annotation.ControllerAdvice"/> </context:component-scan> <!-- 定义aspectj --> <aop:aspectj-autoproxy proxy-target-class="true"/> <!-- MyBatis配置 --> <bean id="sqlSessionFactory1" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="configLocation" value="classpath:/mybatis/configuration.xml"/> <!-- 自动扫描domain目录, 省掉Configuration.xml里的手工配置 目前model没在一起,只能写typeAliases --> <!--<property name="typeAliasesPackage" value="com.ccut.scos.basic.cargoinfo.model" />--> <!-- 显式指定Mapper文件位置 --> <property name="mapperLocations"> <list> <value>classpath*:/com/**/scos/**/dao/*.xml</value> <value>classpath*:/com/**/steed/dao/mybatis/*.xml</value> <value>classpath*:/com/**/shield/dao/mybatis/*.xml</value> </list> </property> <property name="configurationProperties"> <props> <!-- mapUnderscoreToCamelCase属性将表中列名的下划线映射为JavaBean属性的驼峰式命名,默认为false --> <prop key="mapUnderscoreToCamelCase">true</prop> </props> </property> </bean> <!--多数据源配置,SessionFactory配置--> <bean id="sqlSessionFactory2" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="configLocation" value="classpath:/mybatis/configuration.xml"/> <!-- 自动扫描domain目录, 省掉Configuration.xml里的手工配置 目前model没在一起,只能写typeAliases --> <!--<property name="typeAliasesPackage" value="com.ccut.scos.basic.cargoinfo.model" />--> <!-- 显式指定Mapper文件位置 扫描以-other结尾的xml--> <property name="mapperLocations"> <list> <value>classpath*:/com/genghis/scos/**/dao/*-other.xml</value> <value>classpath*:/com/genghis/steed/dao/mybatis/*.xml</value> <value>classpath*:/com/genghis/shield/dao/mybatis/*.xml</value> </list> </property> <property name="configurationProperties"> <props> <!-- mapUnderscoreToCamelCase属性将表中列名的下划线映射为JavaBean属性的驼峰式命名,默认为false --> <prop key="mapUnderscoreToCamelCase">true</prop> </props> </property> </bean> <!-- 扫描basePackage下所有以@MyBatisRepository标识的接口--> <!--通过sqlSessionTemplateBeanName注入不同数据源--> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.genghis"/> <property name="sqlSessionTemplateBeanName" value="sqlSessionTemplate"/> <property name="annotationClass" value="com.genghis.steed.annotation.mybatisRepository"/> </bean> <!-- hibernate validator --> <bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/> <!--这里的每个key要与数据的key对应,在应用时只需要set相应的key变切换到相应的数据源--> <bean id="sqlSessionTemplate" class="com.sky.scos.common.CustomSqlSessionTemplate"> <constructor-arg ref="sqlSessionFactory1" /> <property name="targetSqlSessionFactorys"> <map> <entry value-ref="sqlSessionFactory1" key="default"/> <entry value-ref="sqlSessionFactory2" key="datasource2"/> </map> </property> </bean> <bean id="transactionManager1" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <tx:annotation-driven transaction-manager="transactionManager1"/> <!--声明多数据源事务--> <bean id="transactionManager2" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource2"/> </bean> <tx:annotation-driven transaction-manager="transactionManager2"/> <bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource"> <property name="basename" value="ViewMessages"/> <!--开发时将cacheSeconds调整为0,则每次访问springMessage都会更新,不需要重启。--> <property name="cacheSeconds" value="-1"/> <property name="defaultEncoding" value="utf-8"/> </bean> <bean id="localeChangeInterceptor" class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor"/> <bean id="localeResolver" class="org.springframework.web.servlet.i18n.SessionLocaleResolver"/> <context:property-placeholder ignore-resource-not-found="true" location="classpath*:/application.properties"/> <!-- 数据源配置,使用应用内的Tomcat JDBC连接池 --> <bean id="dataSource" class="com.sky.scos.common.GenghisDataSource" destroy-method="close"> <property name="driverClassName" value="${jdbc.driver}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> 8dbe <property name="password" value="${jdbc.password}"/> <property name="maxActive" value="${jdbc.pool.maxActive}"/> <property name="maxIdle" value="${jdbc.pool.maxIdle}"/> <property name="defaultAutoCommit" value="true"/> <property name="testOnBorrow" value="true"/> <property name="testOnReturn" value="false"/> <property name="testWhileIdle" value="true"/> <property name="validationQuery" value="select 1"/> <property name="removeAbandonedTimeout" value="600"/> <property name="removeAbandoned" value="true"/> <property name="timeBetweenEvictionRunsMillis" value="30000"/> <property name="minEvictableIdleTimeMillis" value="30000"/> </bean> <bean id="dataSource2" class="com.sky.scos.common.GenghisDataSource" destroy-method="close"> <property name="driverClassName" value="${jdbc.driver}"/> <property name="url" value="${anshangdonglai.url}"/> <property name="username" value="${i.username}"/> <property name="password" value="${i.password}"/> <property name="maxActive" value="${jdbc.pool.maxActive}"/> <property name="maxIdle" value="${jdbc.pool.maxIdle}"/> <property name="defaultAutoCommit" value="true"/> <property name="testOnBorrow" value="true"/> <property name="testOnReturn" value="false"/> <property name="testWhileIdle" value="true"/> <property name="validationQuery" value="select 1"/> <property name="removeAbandonedTimeout" value="600"/> <property name="removeAbandoned" value="true"/> <property name="timeBetweenEvictionRunsMillis" value="30000"/> <property name="minEvictableIdleTimeMillis" value="30000"/> </bean> </beans>
相关文章推荐
- Spring MVC +MyBatis 多数据源配置
- Spring MVC+Mybatis 多数据源配置
- spring+springMVC+mybatis 多数据源配置
- Spring MVC+Mybatis 多数据源配置及发现的几个问题
- SSM(Spring+SpringMVC+MyBatis)框架详细整合和多数据源配置
- SpringMVC+Mybatis 多数据源配置
- SpringMVC+Mybatis 多数据源配置
- maven搭建springmvc+spring+mybatis实例
- SpringMVC+Spring+MyBatis整合笔记
- spring mvc系列文章 - springmvc spring mybatis ibatis freemark整合开发(1.0版)
- Spring+SpringMVC+MyBatis+Maven框架实例
- 基于全注解的Spring3.1 mvc、myBatis3.1、Mysql的轻量级项目
- springmvc spring mybatis结合 - 代码共享
- spring mvc + mybatis事务不起作用
- MyBatis+springMVC+easyUI (dataGirl)实现分页
- 阶梯式使用SpringMVC+MyBatis
- springmvc spring mybatis结合 - 代码共享
- spring+springMVC+mybatis 所需jar包
- mybatis+spring mvc 完美整合方案 查询,保存,更新,删除自动生成
- myBatis + SpringMVC上传、下载文件