继承Spring AbstractRoutingDataSource实现路由切换

原创 2016年05月11日 16:50:08
  • 5680

下面是结合项目整理的如何实现Spring下数据路由动态切换,分三部分,1.配置文件。2.java类。3.总结

一:配置文件

dataAnt.properties:

  1. driverClass1=oracle.jdbc.driver.OracleDriver
  2. jdbcUrl1=jdbc\:oracle\:thin\:@136.160.40.36\:1521\:crmtemp
  3. db.user1=crm_app
  4. db.password1=abc123
  5. driverClass2=oracle.jdbc.driver.OracleDriver
  6. jdbcUrl2=jdbc\:oracle\:thin\:@136.160.40.36\:1521\:crmtest
  7. db.user2=crm_app
  8. db.password2=abc123

配置文件,两个jdbc的配置

sm-spring-db.xml:

  1. <!-- dataAnt默认数据源 -->
  2. <bean id="smDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
  3. <property name="driverClassName" value="${driverClass1}">
  4. </property>
  5. <property name="url" value="${jdbcUrl1}">
  6. </property>
  7. <property name="username" value="${db.user1}">
  8. </property>
  9. <property name="password" value="${db.password1}">
  10. </property>
  11. <property name="accessToUnderlyingConnectionAllowed">
  12. <value>true</value>
  13. </property>
  14. </bean>
  15. <!-- 数据迁移目标数据源 -->
  16. <bean id="qyDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
  17. <property name="driverClassName" value="${driverClass2}">
  18. </property>
  19. <property name="url" value="${jdbcUrl2}">
  20. </property>
  21. <property name="username" value="${db.user2}">
  22. </property>
  23. <property name="password" value="${db.password2}">
  24. </property>
  25. <property name="accessToUnderlyingConnectionAllowed">
  26. <value>true</value>
  27. </property>
  28. </bean>
  29. <!-- 数据路由dataSource-->
  30. <bean id="dataSource" class="com.ai.data.common.LinkageRoutingDataSource">
  31. <property name="targetDataSources">
  32. <map key-type="java.lang.String">
  33. <entry value-ref="smDataSource" key="smDataSource"></entry>
  34. <entry value-ref="qyDataSource" key="qyDataSource"></entry>
  35. </map>
  36. </property>
  37. <property name="defaultTargetDataSource" ref="smDataSource"></property>      <!-- 默认使用ds1的数据源 -->
  38. </bean>

1.这里,配置了两个数据源smDataSource,qyDataSource,并且通过类LinkageRoutingDataSource类实现路由切换。注意设置Bean id为dataSource,保证后面事物控制到对应数据源。

2.bean id = 'dataSource'里注意,必须设置目标数据源targetDataSource和defaultTargetDataSource。

注入jdbcTemplate工具类:

  1. <!--注入JdbcTemplate切换dataSource工具类[获取bean名,重设dataSource] -->
  2. <bean class="com.ai.data.common.JdbcTemplateUtil"></bean>

二:java类

LinkageRoutingDataSource.java

  1. package com.ai.data.common;
  2. import org.apache.commons.lang.StringUtils;
  3. import org.arrow.common.utils.Log;
  4. import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
  5. /**
  6. * 设置数据源
  7. *
  8. * @author weiweiai
  9. * @see [相关类/方法](可选)
  10. * @since [产品/模块版本] (可选)
  11. */
  12. public class LinkageRoutingDataSource extends AbstractRoutingDataSource {
  13. private static final Log log = Log.getLog(LinkageRoutingDataSource.class);
  14. //目标数据源
  15. private static final ThreadLocal<String> TARGET_DATA_SOURCE = new ThreadLocal<String>();
  16. //默认数据源--指标监控的
  17. public static final String DEFAULT_DATA_SOURCE = "smDataSource";
  18. /**
  19. * 根据PrvncUtil类设置进去的当前线程数据源进行数据源切换
  20. *
  21. * @param 无
  22. * @return 数据源名称
  23. */
  24. protected Object determineCurrentLookupKey() {
  25. String targetDataSource = TARGET_DATA_SOURCE.get();
  26. if (StringUtils.isEmpty(targetDataSource)) {
  27. targetDataSource = DEFAULT_DATA_SOURCE; //默认数据源为指标监控数据源
  28. TARGET_DATA_SOURCE.set(targetDataSource);
  29. }
  30. log.debug("当前线程数据源----------------:{}", targetDataSource);
  31. return targetDataSource;
  32. }
  33. /**
  34. * 设置数据源名
  35. * @param target
  36. */
  37. public static void setTargetDataSource(String target) {
  38. TARGET_DATA_SOURCE.set(target);
  39. }
  40. /**
  41. * 取数据源名
  42. * @return
  43. */
  44. public static String getTargetDataSource(){
  45. return TARGET_DATA_SOURCE.get();
  46. }
  47. }

1.实现Spring提供的AbstractRoutingDataSource抽象类,利用ThreadLocal类型来定义TARGET_DATA_SOURCE(目标数据源),保证线程间数据源名不互相影响。

2.指定默认数据源名,对应第一步中bean id =‘smDataSource’

3.determineCurrentLookupKey这个方法,个人理解,如下图:意思应该是说code想建立数据源连接时候,此方法就会执行目的是找到合适数据源。

这里代码里,就是先取TARGET_DATA_SOURCE线程变量里线程安全的TARGET_DATA_SOURCE,取不到就用默认数据源smDataSource。从而实现bean id='dataSource'属性targetDataSources切换。

PrvncUtil.java

  1. package com.ai.data.common;
  2. import org.apache.commons.lang.StringUtils;
  3. import org.arrow.common.utils.Log;
  4. /**
  5. * 设置获取当前线程数据源名称
  6. *
  7. * @date 20150924
  8. * @author weiweiai
  9. */
  10. public class PrvncUtil {
  11. private static final Log LOG_OUTPUT = Log.getLog(PrvncUtil.class);
  12. //默认数据源
  13. public static final String DEFAULT_DATA_SOURCE = "smDataSource";
  14. /**
  15. * 设置需要用的数据源名称
  16. *
  17. * @param dataSourceName 数据源名称
  18. * @retrun 无
  19. */
  20. public static void setDataSourceName(String dataSourceName) {
  21. LinkageRoutingDataSource.setTargetDataSource(getDataSourceName(dataSourceName));
  22. }
  23. /**
  24. * 获取数据源名称
  25. * @param dataSourceName
  26. * @return 数据源名称
  27. */
  28. public static String getDataSourceName(String dataSourceName) {
  29. String dataSource = dataSourceName;
  30. if(StringUtils.isEmpty(dataSource)){
  31. dataSource = DEFAULT_DATA_SOURCE;
  32. }
  33. LOG_OUTPUT.debug("最终获取到的当前数据源名称:{}", dataSource);
  34. //((JdbcTemplate)SpringContextHolder.getBean("jdbcTemplate")).setDataSource((DataSource)SpringContextHolder.getBean(dataSource));
  35. return dataSource;
  36. }
  37. }

数据路由切换工具类

JdbcTemplateUtil.java

  1. package com.ai.data.common;
  2. import javax.sql.DataSource;
  3. import org.springframework.beans.BeansException;
  4. import org.springframework.beans.factory.annotation.Autowired;
  5. import org.springframework.context.ApplicationContext;
  6. import org.springframework.context.ApplicationContextAware;
  7. import org.springframework.jdbc.core.JdbcTemplate;
  8. import com.linkage.bss.commons.util.StringUtil;
  9. /**
  10. * JdbcTemplate工具类,实现切换数据源后JdbcTemplate数据源重设
  11. * @author weiweiai
  12. * 2016/5/10
  13. *
  14. */
  15. public class JdbcTemplateUtil implements ApplicationContextAware{
  16. @Autowired
  17. private JdbcTemplate jdbcTemplate;
  18. public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
  19. this.jdbcTemplate = jdbcTemplate;
  20. }
  21. private ApplicationContext ctx;
  22. /*
  23. * (non-Javadoc)
  24. * @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)
  25. */
  26. public void setApplicationContext(ApplicationContext applicationContext)
  27. throws BeansException {
  28. // TODO Auto-generated method stub
  29. this.ctx = applicationContext;
  30. }
  31. /*
  32. * 取LinkageRoutingDataSource 线程变量中数据源,重设jdbcTemplate的数据源属性
  33. */
  34. public JdbcTemplate getJdbcTemplate(){
  35. String ds = LinkageRoutingDataSource.getTargetDataSource();
  36. if(!StringUtil.isEmpty(ds))
  37. jdbcTemplate.setDataSource((DataSource)ctx.getBean(ds));
  38. return jdbcTemplate;
  39. }
  40. }

1.实现ApplicationContextAware接口,且在第一步中已引入,作用是获取到Spring容器中注入的bean。

2.getJdbcTemplate()方法,先获取LinkageRoutingDataSource类中TARGET_DATA_SOURCE线程变量中保存的数据源名。

3.ds为空,返回的是默认数据源;否则切换jdbcTemplate的数据源。

调用:

  1. PrvncUtil.setDataSourceName("qyDataSource");
  2. primaryValueList = jdbcTemplateUtil.getJdbcTemplate().queryForList((String) dataMap.get("SELFORPRIMARY"));

三:总结

  1. PrvncUtil.setDataSourceName("qyDataSource");

实现了切换:

 

primaryValueList = jdbcTemplateUtil.getJdbcTemplate().queryForList((String) dataMap.get("SELFORPRIMARY"));

实现了:

这里为什么jdbcTemplate已经指到dataSource.而dataSource也已经改变属性targetDataSource却没用,我也不懂,欢迎大神指导原因。我已经亲试,确实需要手工

  1. jdbcTemplate.setDataSource((DataSource)ctx.getBean(ds))

不然数据源切不过来,已验证。

继承Spring AbstractRoutingDataSource实现路由切换的更多相关文章

  1. Spring 实现动态数据源切换--转载 (AbstractRoutingDataSource)的使用

    [参考]Spring(AbstractRoutingDataSource)实现动态数据源切换--转载 [参考] 利用Spring的AbstractRoutingDataSource解决多数据源的问题 ...

  2. 【spring cloud】spring cloud zuul 路由网关

    GitHub源码地址:https://github.com/AngelSXD/springcloud 版本介绍: <properties> <project.build.source ...

  3. spring mvc 多数据源切换,不支持事务控制[一]

    一个项目中需要使用两个数据库,Oracle 和Mysql ,于是参考各个blog,实现此功能.写好后才发现,原来的事务失效了,我去... spring-mybatis.xml 配置 <bean ...

  4. Spring 动态创建并切换数据源

    公司要求后端项目可以进行动态创建并切换数据源,看了网上很多例子大多数使用的都是Spring内置的AbstractRoutingDataSource进行的,使用此方法不是不行但是有诸多缺陷,比如切换时需 ...

  5. 【开发笔记】- AbstractRoutingDataSource动态数据源切换,AOP实现动态数据源切换

    AbstractRoutingDataSource动态数据源切换 上周末,室友通宵达旦的敲代码处理他的多数据源的问题,搞的非常的紧张,也和我聊了聊天,大概的了解了他的业务的需求.一般的情况下我们都是使 ...

  6. AbstractRoutingDataSource动态数据源切换,AOP实现动态数据源切换

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明.本文链接:https://blog.csdn.net/u012881904/article/de ...

  7. 基于AbstractRoutingDataSource实现动态切换数据源

    基于AbstractRoutingDataSource实现动态切换数据源 /**  * DataSource注解接口  */ @Target({ElementType.TYPE, ElementTyp ...

  8. Spring之多数据源切换的应用

    这不是一个新的知识点扩展,顶多算是,Spring的AOP特性的一个应用.那么下面开始今天的学习之旅! 场景 数据库读写分离,或者分库,总之多数据源的场景,怎么样实现自动切换(PS:不考虑各种分库分表的 ...

  9. Spring多数据源动态切换

    title: Spring多数据源动态切换 date: 2019-11-27 categories: Java Spring tags: 数据源 typora-root-url: ...... --- ...

随机推荐

  1. 求平方根C++

    求平方根,正根.曾经都不会.昨天看数学,看到了,写了出来.自己又小优化了一下,非常不错. // squareRoot.cpp -- 2011-08-29-01.04 #include "st ...

  2. Pycharm配置autopep8让Python代码更符合pep8规范

    一.何为pep8? PEP 8官方文档 -- Style Guide for Python Code PEP8中文翻译(转) 二.Pycharm中配置pep8 Pycharm本身是有pep8风格检测的 ...

  3. plsql调用无参/有参存储过程

    --有参调用方式:declare STERMINAL ); SPROCESS NUMBER; begin sj_transfera_digi_getmapping(,,'DYH010006783031 ...

  4. bat薪酬

    三大互联网巨头公司,百度腾讯跟阿里如何划分级别?薪资待遇又有多少?除非身居其位,否则很难探知,但是等你到那个位置知道了,却又不能说,至少不能在公 开场合谈论.接下来就为大家揭秘,百度.阿里与腾讯内部的 ...

  5. 兼容的动态加载JS【原】

    兼容的动态加载JS 屌丝就是悲剧,五一还得宅家里写程序专研技术. 说起动态加载JS,搞web的肯定不陌生,著名的YUI库就有强大的模块化的动态加载JS机制.在代码量不断庞大的今天,动态加载JS作用还是 ...

  6. 卡方检验(Chi-square test/Chi-Square Goodness-of-Fit Test)

    什么是卡方检验 卡方检验是一种用途很广的计数资料的假设检验方法.它属于非参数检验的范畴,主要是比较两个及两个以上样本率( 构成比)以及两个分类变量的关联性分析.其根本思想就是在于比较理论频数和实际频数 ...

  7. hdu1166 敌兵布阵(线段树 求区间和 更新点)

    敌兵布阵 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submi ...

  8. FLume监控文件夹,将数据发送给Kafka以及HDFS的配置文件详解

    详细配置文件flume-conf.properties如下: ############################################ # producer config ###### ...

  9. C语言:字符串读取流读取文件中的数据

    #include<stdio.h> int main() { //定义文件指针 FILE *f = NULL; //打开文件 f = fopen("1.txt",&qu ...

  10. go语言基础之冒泡排序原理

    1.冒泡排序原理 示例: package main //必须有个main包 import "fmt" import "math/rand" import &qu ...