Chinaunix首页 | 论坛 | 博客
  • 博客访问: 12249
  • 博文数量: 1
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 22
  • 用 户 组: 普通用户
  • 注册时间: 2014-03-07 10:29
文章分类

全部博文(1)

文章存档

2014年(1)

我的朋友

分类: Java

2014-10-15 14:56:03

因业务需求,需要连接到两个数据库进行切换,整理了一下Spring+MyBatis的多数据源切换.
先上applicationContext.xml

点击(此处)折叠或打开

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns=""
  3.     xmlns:xsi="" xmlns:context=""
  4.     xmlns:jee="" xmlns:tx=""
  5.     xmlns:aop="" xmlns:p=""
  6.     xmlns:util=""
  7.     xsi:schemaLocation=" /spring-beans-3.0.xsd
  8.                  /spring-context-3.0.xsd
  9.                  /spring-tx-3.0.xsd
  10.                  /spring-jee-3.0.xsd
  11.                  /spring-aop-3.0.xsd /spring-util-3.0.xsd"
  12.     default-autowire="byName">
  13.     <!-- <context:property-placeholder order="1" location="classpath:jdbc.properties" /> -->
  14.     <util:properties id="dataSourceProps" location="classpath:jdbc.properties"/>
  15.     
  16.     <context:component-scan base-package="com.cares" />
  17.     <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
  18.         destroy-method="close">
  19.         <property name="driverClass" value="#{dataSourceProps['com.cares.baseframe.c3p0.driverClass']}" />
  20.         <property name="jdbcUrl" value="#{dataSourceProps['com.cares.baseframe.c3p0.jdbcUrl']}" />
  21.         <property name="user" value="#{dataSourceProps['com.cares.baseframe.c3p0.user']}" />
  22.         <property name="password" value="#{dataSourceProps['com.cares.baseframe.c3p0.password']}" />
  23.         <property name="minPoolSize" value="#{dataSourceProps['com.cares.baseframe.c3p0.minPoolSize']}" />
  24.         <property name="maxPoolSize" value="#{dataSourceProps['com.cares.baseframe.c3p0.maxPoolSize']}" />
  25.         <property name="initialPoolSize" value="#{dataSourceProps['com.cares.baseframe.c3p0.initialPoolSize']}" />
  26.         <property name="maxIdleTime" value="#{dataSourceProps['com.cares.baseframe.c3p0.maxIdleTime']}" />
  27.         <property name="acquireIncrement" value="#{dataSourceProps['com.cares.baseframe.c3p0.acquireIncrement']}" />
  28.         <property name="maxStatements" value="#{dataSourceProps['com.cares.baseframe.c3p0.maxStatements']}" />
  29.         <property name="maxStatementsPerConnection"
  30.             value="#{dataSourceProps['com.cares.baseframe.c3p0.maxStatementsPerConnection']}" />
  31.         <property name="idleConnectionTestPeriod"
  32.             value="#{dataSourceProps['com.cares.baseframe.c3p0.idleConnectionTestPeriod']}" />
  33.         <property name="acquireRetryAttempts"
  34.             value="#{dataSourceProps['com.cares.baseframe.c3p0.acquireRetryAttempts']}" />
  35.         <property name="breakAfterAcquireFailure"
  36.             value="#{dataSourceProps['com.cares.baseframe.c3p0.breakAfterAcquireFailure']}" />
  37.         <property name="testConnectionOnCheckout"
  38.             value="#{dataSourceProps['com.cares.baseframe.c3p0.testConnectionOnCheckout']}" />
  39.     </bean>
  40.     
  41.     
  42.      <bean id="hccDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
  43.        <property name="driverClass" value="#{dataSourceProps['com.cares.hcc.c3p0.driverClass']}" />
  44.         <property name="jdbcUrl" value="#{dataSourceProps['com.cares.hcc.c3p0.jdbcUrl']}" />
  45.         <property name="user" value="#{dataSourceProps['com.cares.hcc.c3p0.user']}" />
  46.         <property name="password" value="#{dataSourceProps['com.cares.hcc.c3p0.password']}" />
  47.         <property name="minPoolSize" value="#{dataSourceProps['com.cares.hcc.c3p0.minPoolSize']}" />
  48.         <property name="maxPoolSize" value="#{dataSourceProps['com.cares.hcc.c3p0.maxPoolSize']}" />
  49.         <property name="initialPoolSize" value="#{dataSourceProps['com.cares.hcc.c3p0.initialPoolSize']}" />
  50.         <property name="maxIdleTime" value="#{dataSourceProps['com.cares.hcc.c3p0.maxIdleTime']}" />
  51.         <property name="acquireIncrement" value="#{dataSourceProps['com.cares.hcc.c3p0.acquireIncrement']}" />
  52.         <property name="maxStatements" value="#{dataSourceProps['com.cares.hcc.c3p0.maxStatements']}" />
  53.         <property name="maxStatementsPerConnection"
  54.             value="#{dataSourceProps['com.cares.hcc.c3p0.maxStatementsPerConnection']}" />
  55.         <property name="idleConnectionTestPeriod"
  56.             value="#{dataSourceProps['com.cares.hcc.c3p0.idleConnectionTestPeriod']}" />
  57.         <property name="acquireRetryAttempts"
  58.             value="#{dataSourceProps['com.cares.hcc.c3p0.acquireRetryAttempts']}" />
  59.         <property name="breakAfterAcquireFailure"
  60.             value="#{dataSourceProps['com.cares.hcc.c3p0.breakAfterAcquireFailure']}" />
  61.         <property name="testConnectionOnCheckout"
  62.             value="#{dataSourceProps['com.cares.hcc.c3p0.testConnectionOnCheckout']}" />
  63.     </bean>
  64.     
  65.     
  66.      <bean id="myDataSource" class="com.cares.baseframe.MultipleDataSource">
  67.         <property name="targetDataSources">
  68.             <map key-type="java.lang.String">
  69.                 <entry value-ref="dataSource" key="my"></entry>
  70.                 <entry value-ref="hccDataSource" key="hcc"></entry>
  71.             </map>
  72.         </property>
  73.         <property name="defaultTargetDataSource" ref="dataSource"></property>
  74.     </bean>
  75.     
  76.     <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
  77.         <property name="configLocation" value="classpath:mybatis-config.xml"></property>
  78.         <property name="dataSource">
  79.             <ref bean="myDataSource" />
  80.         </property>
  81.         <property name="mapperLocations" value="classpath:com/cares/*/*/mapping/*.xml" />
  82.         <property name="typeAliasesPackage" value="com.cares" />
  83.     </bean>
  84.     <bean id="transactionManager"
  85.         class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
  86.         <property name="dataSource" ref="myDataSource" />
  87.     </bean>
  88.     <bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor" />
  89.     
  90.     <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
  91.            <property name="basePackage" value="com.cares.*.*.dao" />
  92.            <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
  93.     </bean>
  94.     
  95.      <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
  96.         <constructor-arg index="0" ref="sqlSessionFactory" />
  97.     </bean>
  98.     
  99.     <!-- import spring timer configuration file
  100.     <import resource="classpath:timer.xml"/>
  101.     -->
  102.     
  103.     <!-- import MyBatis configuration file
  104.     <import resource="classpath:mybatisContext.xml"/>-->
  105.     
  106.     <tx:advice id="webAdvice" transaction-manager="transactionManager">
  107.         <tx:attributes>
  108.             <tx:method name="do*" propagation="REQUIRED" read-only="false" rollback-for="Throwable"/>
  109.             <tx:method name="query*" propagation="REQUIRED" read-only="true" />
  110.             <tx:method name="find*" propagation="REQUIRED" read-only="true" />
  111.             <tx:method name="select*" propagation="REQUIRED" read-only="true" />
  112.         </tx:attributes>
  113.     </tx:advice>
  114.     <aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>
  115.     <bean id="controllerAop" class="com.cares.baseframe.aop.ControllerAop" />
  116.     <aop:config>
  117.         <aop:aspect ref="controllerAop">
  118.             <aop:pointcut id="actionDo"
  119.                 expression="execution(* com.cares.*.*.controller.*Controller.do*())" />
  120.             <aop:around pointcut-ref="actionDo" method="aroundDo" />
  121.         </aop:aspect>
  122.         <aop:aspect ref="controllerAop">
  123.             <aop:pointcut id="actionQuery"
  124.                 expression="execution(* com.cares.*.*.controller.*Controller.query*())" />
  125.             <aop:around pointcut-ref="actionQuery" method="aroundQuery" />
  126.         </aop:aspect>
  127.         <aop:aspect ref="controllerAop">
  128.             <aop:pointcut id="actionFind"
  129.                 expression="execution(* com.cares.*.*.controller.*Controller.find*())" />
  130.             <aop:around pointcut-ref="actionFind" method="aroundFind" />
  131.         </aop:aspect>
  132.     </aop:config>
  133.     <aop:config>
  134.         <aop:pointcut id="allAdvice"
  135.             expression="execution(* com.cares.*.*.service.*.*(..))" />
  136.         <aop:advisor advice-ref="webAdvice" pointcut-ref="allAdvice" />
  137.     </aop:config>
  138.     
  139.     <!-- <import resource="classpath:applicationContext-base.xml"/> -->
  140. </beans>
具体为配置了两个数据源dataSource和hccDataSource,用myDataSource将两个数据源合并,并设置相应键值和默认数据源dataSource
其他工厂类和事务管理的配置不变。
注:因为在service配置了事务一致性,导致在service不能切换数据源,只能在controller层进行切换。

附上相对应切换数据源的MultipleDataSource类代码

点击(此处)折叠或打开

  1. package com.cares.baseframe;

  2. import java.util.Map;

  3. import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

  4. public class MultipleDataSource extends AbstractRoutingDataSource {
  5.     private static final ThreadLocal<String> dataSourceKey = new InheritableThreadLocal<String>();

  6.     public static void setDataSourceKey(String dataSource) {
  7.         dataSourceKey.set(dataSource);
  8.     }

  9.     @Override
  10.     protected Object determineCurrentLookupKey() {
  11.         return dataSourceKey.get();
  12.     }
  13.     
  14.     @Override
  15.     public void setTargetDataSources(Map<Object, Object> targetDataSources) {
  16.         super.setTargetDataSources(targetDataSources);
  17.     }
  18.     
  19.     public static void clear(){
  20.         dataSourceKey.remove();
  21.     }
  22. }
常量类DataSourceInstances

点击(此处)折叠或打开

  1. package com.cares.baseframe;

  2. public class DataSourceInstances{
  3.     public static final String MYDATA="my";
  4.     public static final String HCCDATA="hcc";
  5. }

具体手动切换数据源方法
MultipleDataSource.setDataSourceKey(DataSourceInstances.MYDATA);
MultipleDataSource.setDataSourceKey(DataSourceInstances.HCCDATA);


如果没有配置service层的事务,可以选用自动切换,需要用到拦截器Interceptor
具体在application.xml配置上加上application-base.xml 如下

点击(此处)折叠或打开

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns=""
  3.     xmlns:xsi=""
  4.     xmlns:aop=""
  5.     xmlns:util=""
  6.     xmlns:context=""
  7.     xsi:schemaLocation=" /spring-beans-3.2.xsd
  8.      /spring-util-3.2.xsd
  9.      /spring-aop-3.2.xsd
  10.      /spring-context-3.2.xsd">
  11.  
  12.     <context:component-scan base-package="com.cares.*.*.dao"/>
  13.     <context:component-scan base-package="com.cares.*.*.service.impl"/>
  14.      <context:component-scan base-package="com.hoo.*.interceptor"/>
  15.     
  16.     <!-- 启用Aop AspectJ注解 -->
  17.     <aop:aspectj-autoproxy/>
  18.     
  19.    
  20.     
  21.    
  22.     
  23.       
  24.     <!-- 配置一个拦截器对象,处理具体的切换数据源的业务 -->
  25.     <bean id="dataSourceMethodInterceptor" class="com.cares.baseframe.DataSourceMethodInterceptor"/>
  26.     
  27.     <!-- 参与动态切换数据源的切入点对象 (切入点对象,确定何时何地调用拦截器) -->
  28.     <bean id="methodCachePointCut" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
  29.         <!-- 配置缓存aop切面 -->
  30.         <property name="advice" ref="dataSourceMethodInterceptor" />
  31.         <!-- 配置哪些方法参与缓存策略 -->
  32.         <!--
  33.             .表示符合任何单一字元
  34.             ### +表示符合前一个字元一次或多次
  35.             ### *表示符合前一个字元零次或多次
  36.             ### \Escape任何Regular expression使用到的符号
  37.         -->
  38.         <!-- .*表示前面的前缀(包括包名) 表示print方法-->
  39.         <property name="patterns">
  40.             <list>
  41.                 <value>com.cares.*.*.service.impl.*Service*\.*.*</value>
  42.                  <value>com.cares.*.*.mapper.*Mapper*\.*.*</value>
  43.             </list>
  44.         </property>
  45.     </bean>
  46. </beans>
附上拦截器代码DataSourceMethodInterceptor

点击(此处)折叠或打开

  1. package com.cares.baseframe;

  2. import java.lang.reflect.Proxy;

  3. import org.aopalliance.intercept.MethodInterceptor;
  4. import org.aopalliance.intercept.MethodInvocation;
  5. import org.apache.commons.lang.ClassUtils;
  6. import org.springframework.beans.factory.InitializingBean;
  7.  
  8. /**
  9.  *
  10.  */
  11. public class DataSourceMethodInterceptor implements MethodInterceptor, InitializingBean {
  12.  
  13.     @Override
  14.     public Object invoke(MethodInvocation invocation) throws Throwable {
  15.         Class<?> clazz = invocation.getThis().getClass();
  16.         String className = clazz.getName();
  17.         if (ClassUtils.isAssignable(clazz, Proxy.class)) {
  18.             className = invocation.getMethod().getDeclaringClass().getName();
  19.         }
  20.         String methodName = invocation.getMethod().getName();
  21.         Object[] arguments = invocation.getArguments();
  22.         
  23.         if (className.contains("Hcc")) {
  24.             MultipleDataSource.setDataSourceKey("hcc");
  25.         }else{
  26.             MultipleDataSource.setDataSourceKey(DataSourceInstances.MYDATA);
  27.         }
  28.         
  29.         Object result = invocation.proceed();
  30.         return result;
  31.     }
  32.  
  33.     @Override
  34.     public void afterPropertiesSet() throws Exception {
  35. // log.trace("afterPropertiesSet……");
  36.     }
  37. }





阅读(4945) | 评论(1) | 转发(0) |
0

上一篇:没有了

下一篇:没有了

给主人留下些什么吧!~~

江_南2015-05-20 14:58:33

问下如果配置了事物就不能自动切换?  Spring 多个数据源的事物有问题?