继承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. pig—WordCount analysis

    grunt> cat /opt/dataset/input.txt keyword1 keyword2 keyword2 keyword4 keyword3 keyword1 keyword4 ...

  2. iOS Sprite Kit最新特性Physics Field虚拟物理场Swift測试

    在WWDC2014上,Sprite Kit又有了非常多新的提升! 当中一个非常有意思的东西就是Physics Field!也就是物理场! 这意味着我们在Sprite kit上编写虚拟物理场的游戏将变得 ...

  3. 4. API之打印函数

      AbortDoc 取消一份文档的打印 AbortPrinter 删除与一台打印机关联在一起的缓冲文件 AddForm 为打印机的表单列表添加一个新表单 AddJob 用于获取一个有效的路径名,以便 ...

  4. dwz tabs table实现翻页及各tabs查询

    效果如图:

  5. Java读取properties配置文件时,中文乱码解决方法

    public static String getConfig(String key) { Properties pros = new Properties(); String value = &quo ...

  6. 分布式缓存系统Memcached在Asp.net下的应用

    Memcached 是一个高性能的分布式内存对象缓存系统.用于动态Web应用以减轻数据库负载.它通过在内存中缓存数据和对象来降低读取数据库的次数,从而提高动态.数据库驱动站点的速度. Memcache ...

  7. OpenCV学习(24) 直方图(1)

    直方图是对数据的统计,并将统计结果分布于一系列预定义的槽中.这里的数据不仅仅指的是灰度值,它可以是任何能有效描述图像特征的数据,比如图像梯度等等. 假设有一个矩阵包含一张图像的信息 (灰度值 0-25 ...

  8. C语言文件打开方式及说明

    ANSI C规定文件打开用函数fopen,关闭为fclose. 1.调用方式通常为: FILE *fp; fp=fopen(文件名, 打开方式);   2.参数说明: 文件名: 形如"myf ...

  9. 支持5G-WiFi的安卓设备搜索不到5G信号解决方法

    安卓设备必须获得root权限,然后修改 /system/etc/wifi/nvram_net.txt 文件, 将ccode = CN 改为 ccode = ALL.保存并重启即可. 三星EK-GC11 ...

  10. 【SDN】SDN相关资料--了解一下电信领域的SDN

    SDN相关资料 数据中心架构下ospf bgp如何选择及优缺点? - 数据中心 - 知乎 组播扩展OSPF_百度百科 carrier.huawei.com/cn/products/fixed-netw ...