因为公司需求,不同的接口需要连接不同的数据库,在网上找了些资料,最后解决了这个问题
1.首先在db.properties里配置
#dataSource1
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://XXX:3306/xxx?characterEncoding=utf-8&useSSL=false
jdbc.username=root
jdbc.password=root
#dataSource2
jdbc.driver2=com.mysql.jdbc.Driver
jdbc.url2=jdbc:mysql://XXX:3306/xxx?characterEncoding=utf-8&useSSL=false
jdbc.username2=root
jdbc.password2=root
2.自定义注解
package com.xxx.common;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface DataSource {
String value();
}
3.拦截解析注解类DataSourceAspect.java
package com.XXX.common;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import java.lang.reflect.Method;
public class DataSourceAspect{
// 拦截目标方法,获取由@DataSource指定的数据源标识,设置到线程存储中以便切换数据源
public void intercept(JoinPoint point) throws Exception{
Class<?> target = point.getTarget().getClass();
MethodSignature signature=(MethodSignature)point.getSignature();
// 默认使用目标类型的注解,如果没有则使用其实现接口的注解
for (Class<?> clazz : target.getInterfaces()) {
resolveDataSource(clazz, signature.getMethod());
}
resolveDataSource(target, signature.getMethod());
}
/**
* 提取目标对象方法注解和类型注解中的数据源标识
*/
public void resolveDataSource(Class<?>clazz,Method method) {
try {
Class<?>[]types=method.getParameterTypes();
// 默认使用类型注解
if (clazz.isAnnotationPresent(DataSource.class)) {
DataSource source = clazz.getAnnotation(DataSource.class);
DbContextHolder.setDataSource(source.value());
}
// 方法注解可以覆盖类型注解
Method m=clazz.getMethod(method.getName(), types);
if (m!=null && m.isAnnotationPresent(DataSource.class)) {
DataSource source = m.getAnnotation(DataSource.class);
DbContextHolder.setDataSource(source.value());
}
} catch (Exception e) {
System.out.println(clazz+":"+e.getMessage());
}
}
}
4.切换数据库的工具类DbContextHolder.java
package com.xxx.common;
public class DbContextHolder {
//ThreadLocal是一个本地线程副本变量工具类
private static final ThreadLocal<String>THREAD_DATA_SOURCE =new ThreadLocal<String>();
/**
* 设置当前数据库
*/
public static void setDataSource(String dataSource) {
THREAD_DATA_SOURCE.set(dataSource);
}
/**
* 取得当前数据库
*/
public static String getDataSource() {
return THREAD_DATA_SOURCE.get();
}
/**
* 清除上下文数据
*/
public static void clearDataSource() {
THREAD_DATA_SOURCE.remove();
}
}
5.自定义动态数据源
package com.xxx.common;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
public class MultipleDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DbContextHolder.getDataSource();
}
}
6.配置dao.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:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<context:property-placeholder location="classpath:properties/*.properties"/>
<bean id="dataSource1" class="com.alibaba.druid.pool.DruidDataSource"
destroy-method="close">
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="maxActive" value="10"/>
<property name="minIdle" value="5"/>
</bean>
<bean id="dataSource2" class="com.alibaba.druid.pool.DruidDataSource"
destroy-method="close">
<property name="url" value="${jdbc.url2}"/>
<property name="username" value="${jdbc.username2}"/>
<property name="password" value="${jdbc.password2}"/>
<property name="driverClassName" value="${jdbc.driver2}"/>
<property name="maxActive" value="10"/>
<property name="minIdle" value="5"/>
</bean>
<bean id="dataSource" class="com.xxx.xxx.MultipleDataSource">
<!-- 默认数据库 -->
<property name="defaultTargetDataSource" ref="dataSource1"></property>
<property name="targetDataSources">
<map>
<entry key="dataSource1" value-ref="dataSource1"></entry>
<entry key="dataSource2" value-ref="dataSource2"></entry>
</map>
</property>
</bean>
<!-- 切面 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
<bean id="dataSourceAspect" class="com.lyorcw.common.DataSourceAspect"></bean>
<aop:config>
<aop:aspect ref="dataSourceAspect">
<!-- 拦截所有service方法,在dao层添加注解 -->
<aop:pointcut expression="execution(* com.lyorcw.resumesystem.mapper..*.*(..))" id="dataSourcePointcut"/>
<aop:before method="intercept" pointcut-ref="dataSourcePointcut"/>
</aop:aspect>
</aop:config>
<bean class="org.mybatis.spring.SqlSessionFactoryBean" id="sqlSessionFactory">
<property name="dataSource" ref="dataSource"></property>
<property name="configLocation" value="classpath:mybatis/SqlMapConfig.xml"></property>
<property name="mapperLocations" value="classpath:/mapper/*.xml"/>
</bean>
<bean class="tk.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.lyorcw.resumesystem.mapper"/>
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
<property name="properties">
<value>
mappers=tk.mybatis.mapper.common.Mapper
</value>
</property>
</bean>
</beans>
7.只需要在dao层加上注解就行了
package com.xxx.xxx.mapper;
import com.xxx.xxx.DataSource;
import com.xxx.xxx.user.AppResume;
import org.apache.ibatis.annotations.Param;
import tk.mybatis.mapper.common.Mapper;
import java.util.List;
public interface AppResumeMapper extends Mapper<AppResume>{
@DataSource(value = "dataSource2")
AppResume lookResume(AppResume appResume);
}
注解可以加在类上,也可以加在方法上面,方法级别覆盖类级别
8.总结:
步骤:
1.两个数据库分别配置不同id的DataSource
2.配置切换数据库的自定义类的路径,选中默认数据库。
3.配置aop拦截dao层的所有访问接口,在dao层注解更改数据库。
不是原创,记录下来是为了以后用到了方法查看
转载自:https://blog.csdn.net/qq_36746327/article/details/81033404