spring 多数据源切换

1、实现spring的接口

 1 package xxxx;
 2 
 3 import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
 4 
 5 public class DynamicDataSource extends AbstractRoutingDataSource {
 6 
 7     @Override
 8     protected Object determineCurrentLookupKey() {
 9         return DataSourceSwitcher.getDataSourceType();
10     }
11 }

2、绑定线程

 1 package xxxxx;
 2 
 3 import java.util.ArrayList;
 4 import java.util.LinkedHashMap;
 5 import java.util.List;
 6 import java.util.Map;
 7 
 8 import org.apache.commons.lang.StringUtils;
 9 
10 public class DataSourceSwitcher {
11 
12     // 客服系统数据源
13     public static final String DATA_SOURCE_HCRM = "dataSource_hcrm";
14 
15     private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();
16 
17 
18     /**
19      * @Description: 设置数据源类型 @param dataSourceType 数据库类型 @return void @throws
20      */
21     public static void setDataSourceType(String dataSourceType) {
22         contextHolder.set(dataSourceType);
23     }
24 
25     /**
26      * @Description: 获取数据源类型 @param @return String @throws
27      */
28     public static String getDataSourceType() {
29         String dataSource = contextHolder.get();
30         if (StringUtils.isEmpty(dataSource)) {
31             return DataSourceSwitcher2.DATA_SOURCE_HCRM;
32         } 
33         return dataSource;
34     }
35 
36     /**
37      * @Description: 清除数据源类型 @param @return void @throws
38      */
39     public static void clearDataSourceType() {
40         contextHolder.remove();
41     }
42 }

3、操作数据库之前切换数据源

public int insert(String dataSourceCode, String sqlMapId, Object object){
        DataSourceSwitcher.setDataSourceType(dataSourceCode);
        return myBatisDAO.insert(sqlMapId, object);
    }

4、配置动态数据源

 1  <bean id="data_source_2_0" parent="dataSource" init-method="init"
 2     destroy-method="close">
 3     <property name="url" value="${jdbc-2_0.url}" />
 4     <property name="username" value="${jdbc-2_0.user}" />
 5     <property name="password" value="${jdbc-2_0.password}" />
 6 </bean>
 7 
 8 <!-- 数据源动态映射 -->
 9 <!-- 这种动态数据源在分布式事务时 目前做不到,这种情况可能要用JPA分布式事务-->
10 <bean id="dynamicDataSource" class="xxx.DynamicDataSource">
11     <property name="targetDataSources">
12         <map>
13             <entry key="xxxx" value-ref="xxxx" />
14             <entry key="data_source_2_0" value-ref="data_source_2_0" />
15         </map>
16     </property>
17     
18 </bean>
19 
20 <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
21     <property name="dataSource" ref="dynamicDataSource" />
22     <property name="configLocation" value="classpath:db/sql_map_service_config.xml" />
23 </bean>
24 <!-- 复杂的操作可以用到 和 DataSourceSwitcher.switchDataSource 配合适用,切换数据库-->
25 <!-- 如果涉及到事务,需要spring的声明事务,目前的想到的方法是加入拦截器 在开启事务之前切换数据源,aop建议切入到dao层 -->
26 <!-- 也就是说 :在一次业务处理中, 如果涉及到多数据库操作,同时又需要加入事务,建议把对一个数据库操作操作放到一个dao中,切dao层-->

如果没有数据库的事务管理,已经可以实现数据库的动态切换了。但是如果涉及到数据库的事务管理,需要在数据库事务开启切换数据库,
可以定义一个aop处理类在数据库事务开启之前切换数据库

 1 public class DataSourceAspect implements MethodBeforeAdvice,AfterReturningAdvice 
 2 {
 3 
 4     @Override
 5     public void afterReturning(Object returnValue, Method method,
 6             Object[] args, Object target) throws Throwable {
 7         // TODO Auto-generated method stub
 8         DataSourceContextHolder.clearDataSourceType();
 9     }
10 
11     @Override
12     public void before(Method method, Object[] args, Object target)
13             throws Throwable {
14     
15         if (method.isAnnotationPresent(DataSource.class)) 
16         {
17             //DataSource datasource = method.getAnnotation(DataSource.class);
18             DataSourceContextHolder.setDataSourceType("XXXXXXXXXX");
19         }
20         else
21         {
22             DataSourceContextHolder.setDataSourceType("xxxxxxxxxxxxxxxx");
23         }
24         
25     }
26 }

设置数据库事务切面和切换数据库切面执行的顺序

1 <aop:config>
2         <aop:pointcut id="abc" expression="execution(* com.test.service.*.*(..))" />
3         <aop:advisor pointcut-ref="abc"
4             advice-ref="txAdvice" order="2" />
5         <aop:advisor advice-ref="dataSourceAspect" pointcut-ref="abc" order="1"/>
6     </aop:config>

总结:

posted on 2017-05-23 16:55  祥昊  阅读(322)  评论(0)    收藏  举报

导航