基于注解的Spring多数据源配置和使用(非事务)
1。创建DynamicDataSource类,继承AbstractRoutingDataSource
package com.rps.dataSource;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
public class DynamicDataSource extends AbstractRoutingDataSource {
    @Override
    protected Object determineCurrentLookupKey() {
        return DynamicDataSourceHolder.getDataSource();
    }
}
创建DynamicDataSourceHolder类
package com.rps.dataSource;
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();
    }
}
2.配置多数据源
<util:properties id="jdbc"
location="classpath:etc/mybatis/db.properties" /> <!-- 连接池配置开始 -->
<!-- Druid连接池 -->
<bean id="druidDataSourceAccount" class="com.alibaba.druid.pool.DruidDataSource"
destroy-method="close" lazy-init="true">
<property name="driverClassName" value="#{jdbc.driverClassName}" />
<property name="url" value="#{jdbc.account_url}" />
<property name="username" value="#{jdbc.username}" />
<property name="password" value="#{jdbc.password}" />
</bean>
<bean id="druidDataSourceCommon" class="com.alibaba.druid.pool.DruidDataSource"
destroy-method="close" lazy-init="true">
<property name="driverClassName" value="#{jdbc.driverClassName}" />
<property name="url" value="#{jdbc.common_url}" />
<property name="username" value="#{jdbc.username}" />
<property name="password" value="#{jdbc.password}" />
</bean>
<bean id="druidDataSourceData" class="com.alibaba.druid.pool.DruidDataSource"
destroy-method="close" lazy-init="true">
<property name="driverClassName" value="#{jdbc.driverClassName}" />
<property name="url" value="#{jdbc.data_url}" />
<property name="username" value="#{jdbc.username}" />
<property name="password" value="#{jdbc.password}" />
</bean> <!-- 连接池配置结束 --> <!-- MyBatis整合开始 -->
<bean id="dynamicDataSource" class="com.rps.dataSource.DynamicDataSource">
<property name="targetDataSources">
<map key-type="java.lang.String">
<entry key="account" value-ref="druidDataSourceAccount"></entry>
<entry key="common" value-ref="druidDataSourceCommon"></entry>
<entry key="data" value-ref="druidDataSourceData"></entry>
</map>
</property>
</bean> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dynamicDataSource"/>
<property name="mapperLocations" value="classpath:com/rps/**/*.xml"/>
<property name="configLocation" value="classpath:etc/mybatis/mybatis-config.xml"/>
</bean> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.rps" />
<property name="annotationClass" value="com.rps.annotations.MyBatisRepository" />
</bean>
<!-- MyBatis整合结束 --> <!-- 配置数据库事务开始 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dynamicDataSource"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true" />
<!-- 配置数据库事务结束 -->
3.在使用数据源前,选择数据源:
DynamicDataSourceHolder.setDataSource("account");
或:使用spring aop 动态切换:
package com.rps.aspect; import java.lang.annotation.Annotation;
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.reflect.MethodSignature;
import org.springframework.stereotype.Component; import com.rps.annotations.DataSource;
import com.rps.dataSource.DynamicDataSourceHolder; @Component
@Aspect
public class DataSourceAspect {
/**
* 拦截目标方法,获取由@DataSource指定的数据源标识,设置到线程存储中以便切换数据源
*
* @param point
* @throws Exception
*/
@Before("execution(* com.rps.*.model.dao.*.*(..))")
public void intercept(JoinPoint point) throws Exception {
System.out.println("*****************************");
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((Class<? extends Annotation>) 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());
}
}
}
注:事务管理配置一定要配置在往DynamicDataSourceHolder 中注入数据源key之前 ,否则会报 Could not open JDBC Connection for transaction; nested exception is java.lang.IllegalStateException: Cannot determine target DataSource for lookup key [null] 找不到数据源错误
基于注解的Spring多数据源配置和使用(非事务)的更多相关文章
- 基于注解的Spring多数据源配置和使用
		前一段时间研究了一下spring多数据源的配置和使用,为了后期从多个数据源拉取数据定时进行数据分析和报表统计做准备.由于之前做过的项目都是单数据源的,没有遇到这种场景,所以也一直没有去了解过如何配置多 ... 
- 基于xml的Spring多数据源配置和使用
		上一篇讲了<基于注解的Spring多数据源配置和使用>,通过在类或者方法上添加@DataSource注解就可以指定某个数据源.这种方式的优点是控制粒度细,也更灵活. 但是当有些时候项目分模 ... 
- 基于注解的Spring AOP的配置和使用
		摘要: 基于注解的Spring AOP的配置和使用 AOP是OOP的延续,是Aspect Oriented Programming的缩写,意思是面向切面编程.可以通过预编译方式和运行期动态代理实现在不 ... 
- 基于注解实现SpringBoot多数据源配置
		1.功能介绍 在实际的开发中,同一个项目中使用多个数据源是很常见的场景.最近在学习的过程中使用注解的方式实现了一个Springboot项目多数据源的功能.具体实现方式如下. 2.在applicatio ... 
- 基于注解的Spring AOP的配置和使用--转载
		AOP是OOP的延续,是Aspect Oriented Programming的缩写,意思是面向切面编程.可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术. ... 
- spring基于通用Dao的多数据源配置详解【ds1】
		spring基于通用Dao的多数据源配置详解 有时候在一个项目中会连接多个数据库,需要在spring中配置多个数据源,最近就遇到了这个问题,由于我的项目之前是基于通用Dao的,配置的时候问题不断,这种 ... 
- Spring系列9:基于注解的Spring容器配置
		写在前面 前面几篇中我们说过,Spring容器支持3种方式进行bean定义信息的配置,现在具体说明下: XML:bean的定义和依赖都在xml文件中配置,比较繁杂. Annotation-based ... 
- Spring7:基于注解的Spring MVC(下篇)
		Model 上一篇文章<Spring6:基于注解的Spring MVC(上篇)>,讲了Spring MVC环境搭建.@RequestMapping以及参数绑定,这是Spring MVC中最 ... 
- 基于注解的Spring AOP入门、增强Advice实例
		这篇文章简单通过一个例子,介绍几种增强的基本配置,以方便spring框架初学者对aop的代码结构有个清楚的了解认识.首先,spring支持aop编程,支持aspectJ的语法格式来表示切入点,切面,增 ... 
随机推荐
- android 自定义控件---圆形方向盘
			在做Android平台开发的时候,经常会遇到安卓原生控件无法满足需求的情况,安卓允许开发者去继承已经存在的控件或者实现你自己的控件. 先来看一下效果图 采用直接集成View类,重写onDrow方法绘制 ... 
- 基于Bootstrap的遮罩层,带有加载提示
			1.body中的html <div class="modal fade" id="loadingModal"> <div style=&quo ... 
- nodejs+react构建仿知乎的小Demo
			一.命令行进入指定项目文件夹 二.相关命令安装环境和项目工具 npm init npm install react -- save npm install -g gulp npm install -- ... 
- 51nod 1873 高精度计算
			JAVA BigDecimal import java.util.*; import java.math.*; public class Main { public static void main( ... 
- 图论:最短路-SPFA
			该算法由Bellman-Ford算法演变过来,首先介绍一下Bellman-Ford算法 最短路最多经过n-1个点,可以用n-1轮松弛操作来得到 ;i<n;i++) d[i]=INF; d[]=; ... 
- OScached页面缓存知识总结一
			OSCache页面缓存 什么是OSCache? OSCache标记库由OpenSymphony设计,它是一种开创性的JSP定制标记应用,提供了在现有JSP页面之内实现快速内存缓冲的功能.OSCache ... 
- asp.net 权限管理系统
			asp.net webform ,基于组织机构.角色的权限管理系统. 网上找的,挺好.随拿来分享. https://bitbucket.org/zzhi/asp.net 
- LESS使用简介!
			我真的真的极度痛苦. 原本用了那么久的LESS,一直都是用编译工具(考拉)进行编译的,今天试了试用less.js来搞,按官网的都一毛一样,然而!就是编译不出来! 我用来擦鼻涕的卫生纸都一下午用了大半卷 ... 
- setTimeout()和setInterval()方法的区别
			setTimeout(); //5秒后执行yourFunction(),只执行一次 setInterval(); //每隔5秒执行一次 1.setTimeout(funhander,time)的作用是 ... 
- Python 下调用C动态链接库 -- (转)
			在linux开发的动态链接库需要被python调用,首先需要生成.so文件. 生成动态链接库的方法网上有很多,主要就是首先根据源文件编译生成.o,然后链接这些.o文件-shared生成.so.需要注意 ... 
