配置单数据源
配置多数据源
- 简介:该方案是基于注解、切面的方式实现SSM多数据源
- db.properties的配置
jdbc.url.db1=jdbc:mysql://ip1:3306/db1?useUnicode=true&characterEncoding=utf-8
jdbc.username.db1=root
jdbc.password.db1=******
jdbc.url.db2=jdbc:mysql://ip2:3306/db2?useUnicode=true&characterEncoding=utf-8
jdbc.username.db2=root
jdbc.password.db2=******
- applicationContext-db.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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<!-- 加载数据源配置文件 -->
<context:property-placeholder
location="classpath:db.properties" />
<bean name="dataSource1"
class="com.alibaba.druid.pool.DruidDataSource" init-method="init"
destroy-method="close">
<property name="url" value="${jdbc_url_db1}" />
<property name="username" value="${jdbc_username_db1}" />
<property name="password" value="${jdbc_password_db1}" />
<!-- 初始化连接大小 -->
<property name="initialSize" value="4" />
<!-- 连接池最大使用连接数量 -->
<property name="maxActive" value="400" />
<!-- 连接池最小空闲 -->
<property name="minIdle" value="4" />
<!-- 获取连接最大等待时间 -->
<property name="maxWait" value="5000" />
<property name="validationQuery" value="${validationQuery}" />
<property name="validationQueryTimeout" value="1" />
<property name="testOnBorrow" value="false" />
<property name="testOnReturn" value="false" />
<property name="testWhileIdle" value="true" />
<!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
<property name="timeBetweenEvictionRunsMillis" value="60000" />
<!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
<property name="minEvictableIdleTimeMillis" value="300000" />
<!-- 打开removeAbandoned功能 -->
<property name="removeAbandoned" value="true" />
<!-- 1800秒,也就是30分钟 -->
<property name="removeAbandonedTimeout" value="1800" />
<!-- 关闭<u>abanded</u>连接时输出错误日志 -->
<property name="logAbandoned" value="true" />
<!-- 监控数据库 -->
<property name="filters" value="mergeStat" />
</bean>
<bean name="dataSource2"
class="com.alibaba.druid.pool.DruidDataSource" init-method="init"
destroy-method="close">
<property name="url" value="${jdbc_url_db2}" />
<property name="username" value="${jdbc_username_db2}" />
<property name="password" value="${jdbc_password_db2}" />
<!-- 初始化连接大小 -->
<property name="initialSize" value="4" />
<!-- 连接池最大使用连接数量 -->
<property name="maxActive" value="400" />
<!-- 连接池最小空闲 -->
<property name="minIdle" value="4" />
<!-- 获取连接最大等待时间 -->
<property name="maxWait" value="5000" />
<property name="validationQuery" value="${validationQuery}" />
<property name="validationQueryTimeout" value="1" />
<property name="testOnBorrow" value="false" />
<property name="testOnReturn" value="false" />
<property name="testWhileIdle" value="true" />
<!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
<property name="timeBetweenEvictionRunsMillis" value="60000" />
<!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
<property name="minEvictableIdleTimeMillis" value="300000" />
<!-- 打开removeAbandoned功能 -->
<property name="removeAbandoned" value="true" />
<!-- 1800秒,也就是30分钟 -->
<property name="removeAbandonedTimeout" value="1800" />
<!-- 关闭<u>abanded</u>连接时输出错误日志 -->
<property name="logAbandoned" value="true" />
<!-- 监控数据库 -->
<property name="filters" value="mergeStat" />
</bean>
<bean id="dataSourceRouter"
class="com.fei.demo.common.config.DataSourceRouter" lazy-init="true">
<!-- 这里可以指定默认的数据源 -->
<property name="defaultTargetDataSource" ref="dataSource1" />
<property name="targetDataSources">
<map key-type="java.lang.String">
<!-- 指对应的数据源 -->
<entry key="dataSource1" value-ref="dataSource1"></entry>
<entry key="dataSource2" value-ref="dataSource2"></entry>
</map>
</property>
</bean>
<!-- 配置MyBatis sqlsessionFactory -->
<bean id="sqlsessionFactory"
class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSourceRouter" />
<!-- 引入MyBatis核心配置文件 -->
<property name="configLocation" value="classpath:MyBatis.xml" />
<!-- 引入Mapping配置文件 -->
<property name="mapperLocations">
<list>
<value>classpath:com/fei/demo/mapper/*.xml</value>
</list>
</property>
</bean>
<!-- 配置sqlSessionTemplate -->
<bean id="sqlSessionTemplate" scope="prototype"
class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg index="0" ref="sqlsessionFactory" />
</bean>
</beans>
- 编写
DataSourceRouter
类
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
public class DataSourceRouter extends AbstractRoutingDataSource{
@Override
protected Object determineCurrentLookupKey() {
String dataSource = HandleDataSource.getDataSource();
return dataSource;
}
}
- 编写
HandleDataSource
类
public class HandleDataSource {
private static final ThreadLocal<String> holder = new
ThreadLocal<String>();
public static void setDataSource(String datasource) {
holder.set(datasource);
}
public static String getDataSource() {
return holder.get();
}
public static void clearDataSource() {
holder.remove();
}
}
- 编写
DataSource
注解
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();
}
- 编写
DataSourceAspect
切面类
import java.lang.reflect.Method;
import java.text.MessageFormat;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import com.fei.demo.common.annotation.DataSource;
@Aspect
@Component
@Order(1)
@EnableAspectJAutoProxy(proxyTargetClass=true)
public class DataSourceAspect {
static Logger logger = LoggerFactory.getLogger(DataSourceAspect.class);
// 拦截dao层的所有方法
@Pointcut("execution(* com.fei.demo.*.dao..*.*(..))")
public void aspect() {}
@Before("aspect()")
public void before(JoinPoint point) {
Class<?> target = point.getTarget().getClass();
MethodSignature signature = (MethodSignature) point.getSignature();
Method method = signature.getMethod() ;
DataSource dataSource = null ;
dataSource = this.getDataSource(target, method) ;
if(dataSource == null){
for (Class<?> clazz : target.getInterfaces()) {
dataSource = getDataSource(clazz, method);
if(dataSource != null){
break ;
}
}
}
if(dataSource != null && !"".equals(dataSource.value()) ){
HandleDataSource.setDataSource(dataSource.value());
}
}
@After("aspect()")
public void after(JoinPoint point) {
HandleDataSource.setDataSource(null);
}
public DataSource getDataSource(Class<?> target, Method method){
try {
Class<?>[] types = method.getParameterTypes();
Method m = target.getMethod(method.getName(), types);
if (m != null && m.isAnnotationPresent(DataSource.class)) {
return m.getAnnotation(DataSource.class);
}
if (target.isAnnotationPresent(DataSource.class)) {
return target.getAnnotation(DataSource.class);
}
} catch (Exception e) {
e.printStackTrace();
logger.error(MessageFormat.format("通过注解切换数据源时发生异常[class={0},method={1}]:"
, target.getName(), method.getName()),e) ;
}
return null ;
}
}
- 在
Dao
层使用DataSource
注解,不加注解使用的是默认的数据源
@Repository
@Mapper
@DataSource("dataSource2")
public interface Test2Dao{
testList();
}
@Repository
@Mapper
@DataSource("dataSource1")
public interface Test1Dao{
testList();
}
- 至此
SSM
配置多数据源成功
网友评论