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>
总结:
浙公网安备 33010602011771号