首先在properties中配置多个数据源的连接信息 system.driver=com.mysql.jdbc.Driver system.url=jdbc:mysql://192.168.23.129:3306/qingcheng_system?characterEncoding=UTF-8 system.username=root system.password=962464110
goods.driver=com.mysql.jdbc.Driver goods.url=jdbc:mysql://192.168.23.129:3306/qingcheng_goods?characterEncoding=UTF-8 goods.username=root goods.password=962464110 然后再xml中配置连接:
<bean id="dataSource_system"
class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
<property name="username" value="${system.username}" />
<property name="password" value="${system.password}" />
<property name="driverClassName" value="${system.driver}" />
<property name="url" value="${system.url}" />
</bean>
<bean id="dataSource_goods"
class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
<property name="username" value="${goods.username}" />
<property name="password" value="${goods.password}" />
<property name="driverClassName" value="${goods.driver}" />
<property name="url" value="${goods.url}" />
</bean>
<bean id = "dataSource" class="com.six.pool.DynamicDataSource">
<property name="targetDataSources">
<map key-type="java.lang.String">
<!--增加数据源-->
<entry value-ref="dataSource_system" key="dataSource_system"></entry>
<entry value-ref="dataSource_goods" key="dataSource_goods"></entry>
</map>
</property>
<!--默认连接-->
<property name="defaultTargetDataSource" ref="dataSource_goods" />
</bean>
编写工具类,和继承determinecurrentlookupkey public class DynamicDataSourceHolder { private static final ThreadLocal THREAD_DATA_SOURCE = new ThreadLocal();
public static String getDataSource()
{
return (String)THREAD_DATA_SOURCE.get();
}
public static void setDataSource(String dataSource)
{
THREAD_DATA_SOURCE.set(dataSource);
}
public static void clearDataSource()
{
THREAD_DATA_SOURCE.remove();
}
}
public class DynamicDataSource extends AbstractRoutingDataSource { @Override protected Object determineCurrentLookupKey() {
// 从自定义的位置获取数据源标识
return DynamicDataSourceHolder.getDataSource();
}
} 调用的时候直接set就可以了,例如 public List
findMenu() { DynamicDataSourceHolder.setDataSource("dataSource_system");
//查找出一级菜单
List<Menu> list = menuDao.findMenu();
//查找二级菜单
for (Menu menu : list) {
String pid = menu.getPath();
List<Menu> list2 = menuDao.findMenuByPid(pid);
//查找三级菜单
for (Menu menu1 : list2) {
String pid1 = menu1.getPath();
List<Menu> list3 = menuDao.findMenuByPid(pid1);
menu1.setChildren(list3);
}
menu.setChildren(list2);
}
return list;
}
如果有多个方法需要设置其他的数据库,可以使用注解的方式:下面的代码是基于上面的代码书写,并且加入注解后,即使有事务控制,也不会失效: 写入自定义注解: package com.six.pool;
import java.lang.annotation.*;
import static java.lang.annotation.ElementType.METHOD; import static java.lang.annotation.ElementType.TYPE; import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Target({ TYPE, METHOD }) @Retention(RUNTIME) public @interface DataSource { String value(); } 注解使用类: package com.six.pool;
import org.aspectj.lang.JoinPoint; import org.aspectj.lang.reflect.MethodSignature;
import java.lang.reflect.Method;
public class DataSourceAspect {
/**
* 拦截目标方法,获取由@DataSource指定的数据源标识,设置到线程存储中以便切换数据源
*
* @param
* @throws Exception
*/
public void intercept(JoinPoint joinPoint) throws Exception {
//获取切入点的类反射
Class<?> targetClass=joinPoint.getTarget().getClass();
//获取方法参数
MethodSignature signature=(MethodSignature) joinPoint.getSignature();
for(Class<?> clazz:targetClass.getInterfaces())
{
dealDataSource(clazz,signature.getMethod());
}
//默认使用目标类型的注解,如果没有则使用其实现的接口注解
dealDataSource(targetClass, signature.getMethod());
}
/**
* 提取目标对象方法注解和类型注解中的数据源标识
*
* @param clazz
* @param method
*/
private void dealDataSource(Class<?> clazz, Method method) {
try
{
//获取方法参数
Class<?>[] paramTypeArr=method.getParameterTypes();
//检查是否为MDataSource注解
if(clazz.isAnnotationPresent(DataSource.class))
{
//获取注解对象
DataSource dataSource=clazz.getAnnotation(DataSource.class);
DynamicDataSourceHolder.setDataSource(dataSource.value());
}
//方法注解,可以覆盖类型注解
Method m=clazz.getMethod(method.getName(), paramTypeArr);
if(m!=null && m.isAnnotationPresent(DataSource.class))
{
DataSource dataSource=m.getAnnotation(DataSource.class);
DynamicDataSourceHolder.setDataSource(dataSource.value());
}
} catch (Exception e)
{
System.out.println(clazz + ":" + e.getMessage());
}
}
}
在xml中配置自定义切入点aop拦截方法:
<bean id="dataSourceAspect" class="com.six.pool.DataSourceAspect"></bean>
<aop:config>
<aop:aspect ref="dataSourceAspect" id="myAspect">
<aop:pointcut expression="execution(* com.six.service.serviceimpl.*.*(..))" id="pointcut"/>
<aop:before pointcut-ref="pointcut" method="intercept"/>
</aop:aspect>
</aop:config>
如果添加事务后,注解方法更换数据库也失效,可尝试控制事务的传播级别:(非必须) 作者不需要控制,依然可以使用注解的方式更换数据库 @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)