目录
一、最简单的配置方法
1、在datasource.properties文件配置数据源信息
jdbc.driverClassName = com.mysqL.jdbc.Driver
jdbc.urL = jdbc:mysqL://localhost:3306/one
jdbc.username = test1
jdbc.password = 123
jdbc.driverClassName2 = com.mysqL.jdbc.Driver
jdbc.urL2 = jdbc:mysqL://localhost:3307/one
jdbc.username2 = test2
jdbc.password2 = 123
2、SSM项目需要在XML里面进行相关配置
<!--第一个数据库-->
<bean id="One_dataSource" class= "org.apache.commons.dbcp.BasicDataSource" destroy -method="close">
<property name= "driverClassName" value=" ${jdbc.driverCLassName}" />
<property name="urL" value="${jdbc.urL}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
<property name= "maxActive" value= "30"/>
<property name="maxIdle" value="20" />
<property name="maxWait" value="60000" />
</bean>
<!--第二个数据库-->
<bean id="Two_dataSource" class= "org.apache.common.dbcp.BasicDataSource" destroy -method="close">
<property name= "driverClassName" value=" ${jdbc.driverCLassName2}" />
<property name="urL" value="${jdbc.urL2}" />
<property name="username" value="${jdbc.username2}" />
<property name="password" value="${jdbc.password2}" />
<property name= "maxActive" value= "30"/>
<property name="maxIdle" value="20" />
<property name="maxWait" value="60000" />>
</bean>
3、对两个数据源进行相关配置
<bean id="dataSourceAspect" class="com.javal.util.DataSwitchAop" />
<aop:config>
<aop:aspect ref="dataSourceAspect" >
<!-- 拦截所有service方法 -->
<!--我这里实在service上面加的注解,可自行调换 -->
<aop:pointcut id="dataSourcePointcut" expression="execution(* com.javal.service..*.*(..))"/>
<aop:before pointcut-ref="dataSourcePointcut" method="intercept" />
</aop:aspect>
</aop:config>
<!--启动对@AspectJ注解的支持 , proxy-target-class设置为true表示通知spring使用cglib而不是jdk的来生成代理方法,这样AOP可以拦截到Controller -->
<aop:aspectj-autoproxy proxy-target-class="true"/>
<!--配置指定的类-->
<bean id="dataSource" class= "com.yjy.util.DynamicDataSource">
<property name ="targetDataSources">
<map key-type="java.Lang.String">
<--指定LookupKey和与之对应的数据源,这里的key可以自行定义,要切换数据库的时候以key为标识,不要写错- ->
<entry key= "One_dataSource" value-ref= "One_dataSource "></entry>
<entry key= "Two_dataSource" value-ref= "Two_dataSource "></ entry>
</map>
</property>
<--这里可以指定默认的数据源->
<property name= "defauttTargetDataSource" ref= "One_dataSource "></property>
</bean>
<!-- DAO接口所在包名,Spring会自动查找其下的类 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.javal.dao" />
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
</bean>
<!-- sql会话模版 -->
<bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate" scope="prototype">
<constructor-arg ref="sqlSessionFactory"/>
</bean>
<!--事务控制-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
4、程序中调用需要的库
4.1 新建DynamicDataSource类
我们先要重写determineCurrentLookupKey方法,我们新建一个创建一个DynamicDataSource的类,用来获取自定义获取数据源的标识(和当前线程中使用的数据源):
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
// 从自定义的位置获取数据源标识
return DynamicDataSourceHolder.getDataSource();
}
}
4.2 新建DynamicDataSourceHolder类
public class DynamicDataSourceHolder{
private static final ThreadLocal<String> 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();
}
}
4.3 调用方法更换数据源
public void data() {
JSONObject jsonObject = new JSONObject();
List<Map<String ,Object>> list = testmapper.selectAllColor();
jsonObject.put("AllColor",list);
//切换数据源
DynamicDataSourceHolder.setDataSource( "Two_dataSource") ;
testmapper.addAllColor();
}
注意:因为配置了默认数据源,所以默认为第一个数据源,需要切换数据源的时候再进行切换。
建议:如果切换了数据源,需要在继续操作默认数据源的时候,建议切换回默认数据源。
二、注解方式
相关配置与简单方法大同小异,程序中调用的方法改成如下即可:
1、添加依赖
<dependency>
<groupId>aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.5.2</version>
</dependency>
2、相关类
(1)自定义注解:DataSource (后面测试时切换数据源时使用)
import java.lang.annotation.*;
//设置注解
@Retention(RetentionPolicy.RUNTIME)
@Target({
ElementType.METHOD, ElementType.TYPE})
@Documented
public @interface DataSource {
String value() default "";
}
(2)DataSwitchAop类
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import com.zyl.crm.util.DynamicDataSourceHolder;
import java.lang.reflect.Method;
public class DataSwitchAop {
/**
* 拦截目标方法,获取由@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());
}
/**
* 提取目标对象方法注解和类型注解中的数据源标识
*/
private void resolveDataSource(Class<?> clazz, Method method) {
try {
Class<?>[] types = method.getParameterTypes();
// 默认使用类型注解
if (clazz.isAnnotationPresent(DataSource.class)) {
DataSource source = clazz.getAnnotation(DataSource.class);
DynamicDataSourceHolder.setDataSource(source.value());
}
// 方法注解可以覆盖类型注解
Method m = clazz.getMethod(method.getName(), types);
if (m != null && m.isAnnotationPresent(DataSource.class)) {
DataSource source = m.getAnnotation(DataSource.class);
DynamicDataSourceHolder.setDataSource(source.value());
}
} catch (Exception e) {
System.out.println(clazz + ":" + e.getMessage());
}
}
}
(3)DynamicDataSourceHolder 类
public class DynamicDataSourceHolder {
private static final ThreadLocal<String> dataSourceKey = new InheritableThreadLocal<String>();
public static String getDataSource(){
return dataSourceKey.get();
}
public static void setDataSource(String dataSource){
dataSourceKey.set(dataSource);
}
public static void clearDataSource(){
dataSourceKey.remove();
}
}
(4)DynamicDataSource类
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import org.springframework.transaction.reactive.AbstractReactiveTransactionManager;
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DynamicDataSourceHolder.getDataSource();
}
}
3、测试
以下代码应该写在service中
@DataSource(value = "dataSourcetwo")
public Nas tesx(Integer uid) {
Nas nas1 = nasMapper.selectByPrimaryKey(uid);
return nas1;
}
@DataSource(value = “dataSourcetwo”)只要改变里面的value值即可,value值对应的是我们想找的数据源