项目中需要用到连个数据源的连接,分别在两个不同的服务器上,地址不同,各自所负责的工作也不同,所以用到了aop的形式配置多数据源的形式,并且加入了注解
1、首先写一下jdbc的配置连接文件,我用的连个都是mysql数据库,其他类型的库也是一样的
A.driver=com.mysql.jdbc.Driver
A.url=jdbc:mysql://127.0.0.1:3306/...?useUnicode=true&characterEncoding=utf8&useSSL=false
A.username=...
A.password=...
#----------------------B servers--------------------------#
B.driver=com.mysql.jdbc.Driver
B.url=jdbc:mysql://localhost:3306/...?useUnicode=true&characterEncoding=utf-8&autoReconnect=true&useSSL=false
B.username=...
B.password=...
#初始化连接大小
jdbc.initialSize=10
#连接池最大数量
jdbc.maxActive=100
#连接池最大空闲
jdbc.maxIdle=1800
#获取连接最大等待时间
jdbc.maxWait=30000
#连接池最小空闲
jdbc.minIdle=20
2.因为我是吧Spring的配置文件和mybatis的配置文件写到一起的,所以就一起展示
spring-mybatis.xml引入aop基本配置
xmlns:aop="http://www.springframework.org/schema/aop"
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
在下方加入aop的配置
<aop:aspectj-autoproxy proxy-target-class="false"/>
spring-mybatis.xml引入配置文件
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<array>
<value>classpath:jdbc.properties</value>
</array>
</property>
</bean>
引入多数据源
<bean id="dataSourceA"
class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${A.driver}"/>
<property name="url" value="${A.url}"/>
<property name="username" value="${A.username}"/>
<property name="password" value="${A.password}"/>
<!-- 初始化连接大小 -->
<property name="initialSize" value="${jdbc.initialSize}"></property>
<!-- 连接池最大数量 -->
<property name="maxActive" value="${jdbc.maxActive}"></property>
<!-- 连接池最大空闲 -->
<property name="maxIdle" value="${jdbc.maxIdle}"></property>
<!-- 连接池最小空闲 -->
<property name="minIdle" value="${jdbc.minIdle}"></property>
<!-- 获取连接最大等待时间 -->
<property name="maxWait" value="${jdbc.maxWait}"></property>
<!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
<property name="timeBetweenEvictionRunsMillis" value="60000" />
<!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
<property name="minEvictableIdleTimeMillis" value="300000" />
<property name="validationQuery" value="SELECT 'x'" />
<property name="testWhileIdle" value="true" />
<property name="testOnBorrow" value="false" />
<property name="testOnReturn" value="false" />
</bean>
<bean id="dataSourceB"
class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${B.driver}"/>
<property name="url" value="${B.url}"/>
<property name="username" value="${B.username}"/>
<property name="password" value="${B.password}"/>
<!-- 初始化连接大小 -->
<property name="initialSize" value="${jdbc.initialSize}"></property>
<!-- 连接池最大数量 -->
<property name="maxActive" value="${jdbc.maxActive}"></property>
<!-- 连接池最大空闲 -->
<property name="maxIdle" value="${jdbc.maxIdle}"></property>
<!-- 连接池最小空闲 -->
<property name="minIdle" value="${jdbc.minIdle}"></property>
<!-- 获取连接最大等待时间 -->
<property name="maxWait" value="${jdbc.maxWait}"></property>
<!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
<property name="timeBetweenEvictionRunsMillis" value="60000" />
<!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
<property name="minEvictableIdleTimeMillis" value="300000" />
<property name="validationQuery" value="SELECT 'x'" />
<property name="testWhileIdle" value="true" />
<property name="testOnBorrow" value="false" />
<property name="testOnReturn" value="false" />
</bean>
<!-- 双数据源 配合 -->
<bean id="dataSource" class="com.firstCapacity.util.aop.ChooseDataSource">
<property name="defaultTargetDataSource" ref="dataSourceA"/>
<property name="targetDataSources">
<map>
<entry key="A" value-ref="dataSourceA"/>
<entry key="B" value-ref="dataSourceB"/>
</map>
</property>
</bean>
其他的包结构扫描基本配置都和大家一样,就不多说了,这里双数据源配置的时候用到了aop的自定义扫描类
ChooseDataSource.java
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
public class ChooseDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
// System.out.println("获取到的数据源为:"+HandleDataSource.getDataSource());
return HandleDataSource.getDataSource();
}
}
DataSourceAspect.java
public class HandleDataSource {
public static final ThreadLocal<String> holder = new ThreadLocal<String>();
public static void putDataSource(String datasource) {
holder.set(datasource);
}
public static String getDataSource() {
return holder.get();
}
}
HandleDataSource.java
public class HandleDataSource {
public static final ThreadLocal<String> holder = new ThreadLocal<String>();
public static void putDataSource(String datasource) {
holder.set(datasource);
}
public static String getDataSource() {
return holder.get();
}
}
自定义的注解:
DataSource.java
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface DataSource {
String value() default "A";
}
在mapper层进行直接转换数据源
DataSourceAspect.java
import java.lang.reflect.Method;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class DataSourceAspect {
@Pointcut("execution(* com.firstCapacity.business.*.mapper..*(..))")
public void pointCut(){};
@Before(value = "pointCut()")
public void before(JoinPoint point)
{
Object target = point.getTarget();
System.out.println(target.toString());
String method = point.getSignature().getName();
System.out.println(method);
Class<?>[] classz = target.getClass().getInterfaces();
Class<?>[] parameterTypes = ((MethodSignature) point.getSignature())
.getMethod().getParameterTypes();
try {
Method m = classz[0].getMethod(method, parameterTypes);
System.out.println(m.getName());
if (m != null && m.isAnnotationPresent(DataSource.class)) {
DataSource data = m.getAnnotation(DataSource.class);
HandleDataSource.putDataSource(data.value());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
最后,我们开始使用一下
在mapper的接口上加入我们自定义的注解进行测试
//按照名称查询
@DataSource("A")
public User getByUsername(String userName);
测试成功,这里默认的是A,也就是说可以不加,但是用到数据源B的地方,就必须要加了