mybatis.xml的配置:
<!-- 动态数据源 -->
<bean id="dataSource" class="org.gyy.dataSource.DynamicDataSource">
<!-- 通过key-value关联数据源 -->
<property name="targetDataSources">
<map>
<entry value-ref="dataSourceOne" key="dataSourceOne" />
<entry value-ref="dataSourceTwo" key="dataSourceTwo" />
</map>
</property>
<property name="defaultTargetDataSource" ref="dataSourceOne" />
</bean>
<!-- 配置数据源(一) -->
<bean name="dataSourceOne" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
<!-- 基本配置 -->
<property name="driverClassName" value="${db1.driverClassName}" />
<property name="url" value="${db1.url}" />
<property name="username" value="${db1.user}" />
<property name="password" value="${db1.password}" />
<!-- 初始化时建立物理连接的个数 -->
<property name="initialSize" value="${db1.initialSize}" />
<!-- 最小连接池数 -->
<property name="minIdle" value="${db1.minIdle}" />
<!-- 最大连接池数量 -->
<property name="maxActive" value="${db1.maxActive}" />
<!-- 配置获取连接等待超时的时间 -->
<property name="maxWait" value="${db1.maxWait}" />
<!-- 数据源监控配置
<property name="filters" value="stat" /> -->
<!-- 多数据源监控配置 -->
<property name="useGlobalDataSourceStat" value="true" />
</bean>
<!-- 配置数据源(二) -->
<bean name="dataSourceTwo" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
<!-- 基本配置 -->
<property name="driverClassName" value="${db2.driverClassName}" />
<property name="url" value="${db2.url}" />
<property name="username" value="${db2.user}" />
<property name="password" value="${db2.password}" />
<!-- 初始化时建立物理连接的个数 -->
<property name="initialSize" value="${db2.initialSize}" />
<!-- 最小连接池数 -->
<property name="minIdle" value="${db2.minIdle}" />
<!-- 最大连接池数量 -->
<property name="maxActive" value="${db2.maxActive}" />
<!-- 配置获取连接等待超时的时间 -->
<property name="maxWait" value="${db2.maxWait}" />
<!-- 数据源监控配置
<property name="filters" value="stat" /> -->
<!-- 多数据源监控配置 -->
<property name="useGlobalDataSourceStat" value="true" />
</bean>
<!-- 配置sqlSessionFactory(由mybatis-spring.jar提供支持) -->
<bean name="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 配置数据源 -->
<property name="dataSource" ref="dataSource" />
<!-- 配置mybatis的默认选项 -->
<property name="configuration" ref="configuration" />
</bean>
<!-- mybatis默认选项配置 -->
<bean id="configuration" class="org.apache.ibatis.session.Configuration">
<property name="callSettersOnNulls" value="true" />
</bean>
<!-- Mapper接口所在包名,Spring会自动查找其下的Mapper -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="org.gyy.mapper..*" />
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
</bean>
<!-- 支持注解事务模式 -->
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true" />
<!-- 事务管理 -->
<bean name="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- 配置声明式事务 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="insert*" propagation="REQUIRED" read-only="false" rollback-for="java.lang.Exception" />
<tx:method name="delete*" propagation="REQUIRED" read-only="false" rollback-for="java.lang.Exception" />
<tx:method name="update*" propagation="REQUIRED" read-only="false" rollback-for="java.lang.Exception" />
<tx:method name="get*" propagation="SUPPORTS" read-only="true" />
</tx:attributes>
</tx:advice>
<!-- 拦截数据源注解,注入数据源 -->
<bean id="dataSourceAspect" class="org.gyy.dataSource.DataSourceAspect" />
<!-- 配置该声明式事务规则用于的切入点 步骤: 1.配置切入点 2.应用该声明式事务规则 -->
<aop:config proxy-target-class="true" expose-proxy="true">
<!-- 配置切入点 -->
<aop:pointcut id="transaction_pointcut" expression="execution(* org.gyy.service.impl..*.*(..))" />
<!-- 应用该声明式事务规则 -->
<aop:advisor advice-ref="txAdvice" pointcut-ref="transaction_pointcut" order="2" />
<aop:aspect ref="dataSourceAspect" order="1">
<!-- 拦截所有service方法 -->
<aop:pointcut id="dataSourcePointcut" expression="execution( * org.gyy.service.impl..*.*(..))" />
<aop:before pointcut-ref="dataSourcePointcut" method="intercept" />
</aop:aspect>
</aop:config>
DynamicDataSource实现类:
package org.gyy.dataSource;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DataSourceContextHolder.getDataSourceType();
}
}
DataSourceContextHolder类:
package org.gyy.dataSource;
public class DataSourceContextHolder {
private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();
/**
* @Description: 设置数据源类型
* @param dataSourceType 数据库类型
* @return void
* @throws
*/
public static void setDataSourceType(String dataSourceType) {
contextHolder.set(dataSourceType);
}
/**
* @Description: 获取数据源类型
* @param
* @return String
* @throws
*/
public static String getDataSourceType() {
return contextHolder.get();
}
/**
* @Description: 清除数据源类型
* @param
* @return void
* @throws
*/
public static void clearDataSourceType() {
contextHolder.remove();
}
}
DataSourceAspect:拦截方法,动态拦截数据源标签实现动态切换:
package org.gyy.dataSource;
import java.lang.reflect.Method;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class DataSourceAspect {
private static final Logger logger = LoggerFactory.getLogger(DataSourceAspect.class);
/**
* 拦截目标方法,获取由@DataSource指定的数据源标识,设置到线程存储中以便切换数据源
*
* @param point
* @throws Exception
*/
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());
}
/**
* 提取目标对象方法注解和类型注解中的数据源标识
*
* @param clazz
* @param method
*/
private void resolveDataSource(Class<?> clazz, Method method) {
try {
Class<?>[] types = method.getParameterTypes();
// 默认使用类型注解
if (clazz.isAnnotationPresent(DataSource.class)) {
DataSource source = clazz.getAnnotation(DataSource.class);
DataSourceContextHolder.setDataSourceType(source.value());
}
// 方法注解可以覆盖类型注解
Method m = clazz.getMethod(method.getName(), types);
if (m != null && m.isAnnotationPresent(DataSource.class)) {
DataSource source = m.getAnnotation(DataSource.class);
DataSourceContextHolder.setDataSourceType(source.value());
}
} catch (Exception e) {
e.printStackTrace();
if (logger.isErrorEnabled()) {
logger.error("DataSourceAspect Error :[{}]", e);
}
}
}
}
自定义数据源标签:
package org.gyy.dataSource;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @date 2017年7月14日
* @version 1.0
* @description 多数据源注解
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD, ElementType.TYPE })
public @interface DataSource {
/**
* @return {@link String}
* @date 2017年7月15日
* @version 1.0
* @description 数据源名称,来源Spring配置
*/
String value();
}
以上的代码就可以实现多数据源的切换了;
这是使用方式,标签里面的值就是自己注入时定义的key,spring也会根据这个去注入。