基于spring来配置和使用多数据源还是比较简单的,因为spring框架已经预留了这样的接口可以方便数据源的切换。
DynamicDataSource类
package com.demo.core;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
// 从自定义的位置获取数据源标识
return DynamicDataSourceHolder.getDataSource();
}
}
DynamicDataSourceHolder类
package com.demo.core;
public class DynamicDataSourceHolder {
/**
* 注意:数据源标识保存在线程变量中,避免多线程操作数据源时互相干扰
*/
private static final ThreadLocal<String> THREAD_DATA_SOURCE = new ThreadLocal<String>();
public static String getDataSource() {
return THREAD_DATA_SOURCE.get();
}
public static void setDataSource(String dataSource) {
THREAD_DATA_SOURCE.set(dataSource);
}
public static void clearDataSource() {
THREAD_DATA_SOURCE.remove();
}
}
package com.demo.core;
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();
}
切面
package com.demo.core;
import java.lang.reflect.Method;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
public class DataSourceAspect {
/**
* 拦截目标方法,获取由@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);
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());
}
}
}
service类
package com.demo.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import com.demo.core.DataSource;
import com.demo.core.DynamicDataSourceHolder;
import com.demo.dao.UserDAO;
import com.demo.model.User;
import com.demo.service.UserService;
@Service
public class UserServiceImpl implements UserService{
@Autowired
@Qualifier("userDAO")
private UserDAO userDAO;
public int insertUser(User user) {
return userDAO.insertUser(user);
}
public User queryUserById(String id) {
return userDAO.queryUserByID(id);
}
@DataSource("dataSource1")//通过元注解 利用切面运行时自动设置数据源
public User queryUserByIdDB2(String id) {
//DynamicDataSourceHolder.setDataSource("dataSource2");
//手动设置数据源
return userDAO.queryUserByID(id);
}
}
dao类
package com.demo.dao;
import org.springframework.stereotype.Repository;
import com.demo.model.User;
@Repository
public interface UserDAO {
public int insertUser(User user);
public User queryUserByID(String id);
}
单元测试service
package test.service;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.demo.service.UserService;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"/conf/spring-mybatis.xml"}) //加载配置文件
public class userServiceTest{
@Autowired
private UserService userservice;
@Test
public void testuserService(){
// System.err.println(userservice.queryUserById("1"));
System.err.println(userservice.queryUserByIdDB2("1"));
}
}
控制台输出
User [id=1, name=数据源1, password=admin1]
User [id=1, name=数据源2, password=admin2]
配置文件
<?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:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-3.2.xsd">
<!-- 引入jdbc配置文件 -->
<context:property-placeholder location="classpath:conf/jdbc.properties"/>
<context:component-scan base-package="com.demo"/>
<!-- mybatis文件配置,扫描所有mapper文件 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"
p:dataSource-ref="dynamicDataSource"
p:configLocation="classpath:conf/mybatis-config.xml"
p:mapperLocations="classpath:mapper/*.xml" />
<!-- configLocation为mybatis属性 mapperLocations为所有mapper -->
<!-- spring与mybatis整合配置,扫描所有dao ,生成与DAO类相同名字的bean(除了首字母小写)-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"
p:basePackage="com.demo.dao" p:sqlSessionFactoryBeanName="sqlSessionFactory" />
<!-- 对数据源进行事务管理 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
p:dataSource-ref="dynamicDataSource" />
<tx:annotation-driven mode="proxy" transaction-manager="transactionManager" />
<!--创建数据源dataSource-->
<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource">
<property name="driverClassName" value="${jdbc_driverClassName}" />
<property name="url" value="${jdbc_url}" />
<property name="username" value="${jdbc_username}" />
<property name="password" value="${jdbc_password}" />
</bean>
<!--创建数据源dataSource2 -->
<bean id="dataSource2" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${db2.driver}" />
<property name="url" value="${db2.url}" />
<property name="username" value="${db2.username}" />
<property name="password" value="${db2.password}" />
</bean>
<bean id="dynamicDataSource" class="com.demo.core.DynamicDataSource">
<property name="targetDataSources">
<map key-type="java.lang.String">
<!-- 指定lookupKey和与之对应的数据源 -->
<entry key="dataSource" value-ref="dataSource"></entry>
<entry key="dataSource2" value-ref="dataSource2"></entry>
</map>
</property>
<!-- 这里可以指定默认的数据源 -->
<property name="defaultTargetDataSource" ref="dataSource" />
</bean>
<bean id="dataSourceAspect" class="com.demo.core.DataSourceAspect"></bean>
<!-- 自定义注解 AOP切换数据源 -->
<aop:config>
<aop:aspect id="concurrentOperationRetry" ref="dataSourceAspect">
<!-- 拦截所有service方法 * com.service.imp.*.*(..)-->
<aop:pointcut id="dataSourcePointcut" expression="execution(* com.demo.service.*.*(..))"/>
<aop:before pointcut-ref="dataSourcePointcut" method="intercept" />
</aop:aspect>
</aop:config>
</beans>
转载 http://www.cnblogs.com/liujiduo/p/5004691.html 基于注解的Spring多数据源配置和使用 推荐
转载 http://blog.csdn.net/wangpeng047/article/details/8866239/ spring多数据源配置
转载 http://download.csdn.net/download/npf_java/8786825 多数据源事务控制