Spring动态配置多数据源,即在大型应用中对数据进行切分,并且采用多个数据库实例进行管理,这样可以有效提高系统的水平伸缩性。而这样的方案就会不同于常见的单一数据实例的方案,这就要程序在运行时根据当时的请求及系统状态来动态的决定将数据存储在哪个数据库实例中,以及从哪个数据库提取数据。

Spring配置多数据源的方式和具体使用过程。 
Spring对于多数据源,以数据库表为参照,大体上可以分成两大类情况: 
一是,表级上的跨数据库。即,对于不同的数据库却有相同的表(表名和表结构完全相同)。 
二是,非表级上的跨数据库。即,多个数据源不存在相同的表。

1、根据用户的选择,使用不同的数据源。

2、解决思路锁定:将sessionFactory的属性dataSource设置成不同的数据源,以达到切换数据源的目的。

3、问题产生:因为整个项目用的几乎都是单例模式,当多个用户并发访问数据库的时候,会产生资源争夺的问题。即项目启动时候,所有的bean都被装载到内存,并且每个bean都只有一个对象。正因为只有一个对象,所有的对象属性就如同静态变量(静态变量跟单例很相似,常用静态来实现单例)。整个项目系统的dataSource只有一个,如果很多用户不断的去改变dataSource的值,那必然会出现资源的掠夺问题,造成系统隐患。

4、多资源共享解决思路:同一资源被抢夺的时候,通常有两种做法,a、以时间换空间 b、以空间换时间。

5、线程同步机制就是典型的“以时间换空间”,采用排队稍等的方法,一个个等待,直到前面一个用完,后面的才跟上,多人共用一个变量,用synchronized锁定排队。   

6、“ThreadLocal”就是典型的“以空间换时间”,她可以为每一个人提供一份变量,因此可以同时访问并互不干扰。

7、言归正传:sessionFactory的属性dataSource设置成不用的数据源,首先不能在配置文件中写死,我们必须为她单独写一个类,让她来引用这个类,在这个类中再来判断我们到底要选择哪个数据源。

spring + mybatis 多数据源切换

DbContextHolder.java

Java代码  
  1. package com.easyway.stage.commons;
  2. public class DbContextHolder
  3. {
  4. // ThreadLocal是线程安全的,并且不能在多线程之间共享。
  5. private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();
  6. public static void setDbType(String dbType)
  7. {
  8. contextHolder.set(dbType);
  9. }
  10. public static String getDbType()
  11. {
  12. return ((String) contextHolder.get());
  13. }
  14. public static void clearDbType()
  15. {
  16. contextHolder.remove();
  17. }
  18. }

MultiDataSource.java

Java代码  
  1. package com.easyway.stage.commons;
  2. import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
  3. public class MultiDataSource extends AbstractRoutingDataSource
  4. {
  5. @Override
  6. protected Object determineCurrentLookupKey()
  7. {
  8. return  DbContextHolder.getDbType();
  9. }
  10. }

applicationContext.xml

Xml代码  
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans
  3. xmlns="http://www.springframework.org/schema/beans"
  4. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
  5. xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jdbc="http://www.springframework.org/schema/jdbc"
  6. xmlns:context="http://www.springframework.org/schema/context"
  7. xsi:schemaLocation="
  8. http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
  9. http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
  10. http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
  11. http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd
  12. http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
  13. <context:annotation-config/>
  14. <!-- 数据源 -->
  15. <bean id="parentDataSource" class="com.alibaba.druid.pool.DruidDataSource">
  16. <!-- 配置初始化大小、最小、最大 -->
  17. <property name="initialSize" value="1" />
  18. <property name="maxActive" value="20" />
  19. <property name="minIdle" value="1" />
  20. <!-- 配置获取连接等待超时的时间60s -->
  21. <property name="maxWait" value="60000" />
  22. <!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
  23. <property name="timeBetweenEvictionRunsMillis" value="60000" />
  24. <!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
  25. <property name="minEvictableIdleTimeMillis" value="300000" />
  26. <property name="validationQuery" value="SELECT 'x'" />
  27. <property name="testWhileIdle" value="true" />
  28. <property name="testOnBorrow" value="false" />
  29. <property name="testOnReturn" value="false" />
  30. <!-- 打开PSCache,并且指定每个连接上PSCache的大小 -->
  31. <property name="poolPreparedStatements" value="true" />
  32. <property name="maxPoolPreparedStatementPerConnectionSize" value="20" />
  33. <!-- 配置监控统计拦截的filters -->
  34. <property name="filters" value="wall,stat,slf4j" />
  35. <!-- 对于长时间不使用的连接强制关闭  -->
  36. <property name="removeAbandoned" value="true" />
  37. <!-- 超过30分钟开始关闭空闲连接 -->
  38. <property name="removeAbandonedTimeout" value="1800" />
  39. <!-- 关闭abanded连接时输出错误日志 -->
  40. <property name="logAbandoned" value="true" />
  41. </bean>
  42. <bean id="local" parent="parentDataSource" init-method="init" destroy-method="close">
  43. <property name="url" value="${local.jdbc.url}" />
  44. <property name="username" value="${local.jdbc.username}" />
  45. <property name="password" value="${local.jdbc.password}" />
  46. </bean>
  47. <bean id="server" parent="parentDataSource" init-method="init" destroy-method="close">
  48. <property name="url" value="${jdbc.url}" />
  49. <property name="username" value="${jdbc.username}" />
  50. <property name="password" value="${jdbc.password}" />
  51. </bean>
  52. <bean id="dataSource" class="com.autrade.stage.commons.MultiDataSource">
  53. <property name="targetDataSources">
  54. <map key-type="java.lang.String">
  55. <entry value-ref="local" key="local"></entry>
  56. <entry value-ref="server" key="server"></entry>
  57. </map>
  58. </property>
  59. <!-- 默认使用server的数据源 -->
  60. <property name="defaultTargetDataSource" ref="server"></property>
  61. </bean>
  62. <!-- MyBatis -->
  63. <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
  64. <property name="dataSource" ref="dataSource" />
  65. <property name="configLocation" value="classpath:resources/mybatis/myBatisConfig.xml" />
  66. <property name="mapperLocations" value="classpath:resources/mybatis/mapper/*.xml"/>
  67. </bean>
  68. <bean class="org.mybatis.spring.SqlSessionTemplate">
  69. <constructor-arg ref="sqlSessionFactory"/>
  70. </bean>
  71. <!-- MyBatis -->
  72. <!-- 配置事务管理对象-->
  73. <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
  74. <property name="dataSource" ref="dataSource"/>
  75. </bean>
  76. <!-- 将所有具有@Transactional注解的Bean自动配置为声明式事务支持 -->
  77. <tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>
  78. <!-- 自定义的拦截器 -->
  79. <bean id="methodAdvisor" class="com.easyway.app.interceptor.InjectorManager" />
  80. <aop:config proxy-target-class="true">
  81. <aop:pointcut id="baseMethods"
  82. expression="execution(* com.easyway.app.service..*.*(..))" />
  83. <aop:advisor advice-ref="methodAdvisor" pointcut-ref="baseMethods" />
  84. </aop:config>
  85. </beans>

Test.java测试类

Java代码  
  1. package com.easyway.stage.test;
  2. import javax.sql.DataSource;
  3. import org.apache.ibatis.session.SqlSession;
  4. import org.apache.ibatis.session.SqlSessionFactory;
  5. import org.mybatis.spring.SqlSessionFactoryBean;
  6. import org.springframework.context.ApplicationContext;
  7. import org.springframework.context.support.ClassPathXmlApplicationContext;
  8. import org.springframework.core.io.FileSystemResource;
  9. import org.springframework.core.io.Resource;
  10. import com.easyway.stage.commons.DbContextHolder;
  11. public class Test
  12. {
  13. /**
  14. * @param args
  15. */
  16. public static void main(String[] args)
  17. {
  18. ApplicationContext appContext = new ClassPathXmlApplicationContext("client-beans.xml");
  19. DbContextHolder.setDbType("local");
  20. String res = "resources/mybatis/myBatisConfig.xml";
  21. DataSource datasource = (DataSource) appContext.getBean("dataSource");
  22. SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
  23. bean.setDataSource(datasource);
  24. Resource resource = new FileSystemResource(res);
  25. bean.setConfigLocation(resource);
  26. try
  27. {
  28. SqlSessionFactory sessionfactory = bean.getObject();
  29. SqlSession session = sessionfactory.openSession();
  30. User user = session.selectOne("com.easyway.mybatis.mapper.findOne");
  31. System.out.println(user.getName());
  32. }
  33. catch (Exception e)
  34. {
  35. e.printStackTrace();
  36. }
  37. DbContextHolder.setDbType("server");
  38. String res1 = "resources/mybatis/myBatisConfig.xml";
  39. DataSource datasource1 = (DataSource) appContext.getBean("dataSource");
  40. SqlSessionFactoryBean bean1 = new SqlSessionFactoryBean();
  41. bean1.setDataSource(datasource1);
  42. Resource resource1 = new FileSystemResource(res1);
  43. bean1.setConfigLocation(resource1);
  44. try
  45. {
  46. SqlSessionFactory sessionfactory = bean.getObject();
  47. SqlSession session = sessionfactory.openSession();
  48. User user = session.selectOne("com.easyway.mybatis.mapper.findOne");
  49. System.out.println(user.getName());
  50. }
  51. catch (Exception e)
  52. {
  53. e.printStackTrace();
  54. }
  55. }
  56. }

spring框架多数据源切换问题的解决相关推荐

  1. spring+mybatis 多数据源切换

    spring+mybatis 多数据源切换 摘自: http://www.oschina.net/code/snippet_347813_12525 1. 代码: DbContextHolder pu ...

  2. spring框架完整配置(后面),以及解决No qualifying bean of type 或Error creating bean with name。。。

    本人刚接触spring,被这问题活活困扰了两天,问题让人快速跳过这坑,特写下此文章共参考. 先说本文下出现的问题. 说下出问题的原因:这是因为我使用了两个spring的配置文件,而在web.xml配置 ...

  3. Spring(AbstractRoutingDataSource)实现动态数据源切换

    参考:http://linhongyu.blog.51cto.com/6373370/1615895 一.前言 近期一项目A需实现数据同步到另一项目B数据库中,在不改变B项目的情况下,只好选择项目A中 ...

  4. Spring(AbstractRoutingDataSource)实现动态数据源切换--转载

    原始出处:http://linhongyu.blog.51cto.com/6373370/1615895 一.前言 近期一项目A需实现数据同步到另一项目B数据库中,在不改变B项目的情况下,只好选择项目 ...

  5. spring mysql 多数据源_spring框架学习【多数据源配置】

    在我们的项目中遇到这样一个问题:我们的项目需要连接多个数据库,而且不同的客户在每次访问中根据需要会去访问不同的数据库.我们以往在spring和hibernate框架中总是配置一个数据源,因而sessi ...

  6. spring boot多数据源动态切换, 多数据源事务管理

    1 . 项目目标 实现 不同数据源的切换 (使用AbstractRoutingDataSource) 不同数据源之间,事物管理,多个数据源之间同时commit或者同时rollback 兼容不同的连接池 ...

  7. spring 动态数据源切换实例

    我们很多项目中业务都需要涉及到多个数据源,最简单的做法就是直接在java代码里面lookup需要的数据源,但是这样的做法很明显耦合度太高了, 而且当逻辑流程不够严谨的时候就会出现各种大家不愿意看到的问 ...

  8. Spring Boot + Mybatis 配合 AOP 和注解实现动态数据源切换配置

    Spring Boot + Mybatis 配合 AOP 和注解实现动态数据源切换配置 前言: 1. 数据库准备: 2. 环境准备: 3.代码部分 4. 测试: 5.等等 6.配合注解实现 7 .测试 ...

  9. spring boot+mybatis 多数据源切换

    由于公司业务划分了多个数据库,开发一个项目会同时调用多个库,经过学习我们采用了注解+aop的方式实现的 1.首先定义一个注解类 @Retention(RetentionPolicy.RUNTIME) ...

最新文章

  1. wordpress 首页调用文章 不同样式的方法
  2. java HashMap实现原理
  3. (数字IC)低功耗设计入门(六)——门级电路低功耗设计优化
  4. 指定Gradle构建属性
  5. 【C语言】结构体赋值
  6. List 、Set、 Map有什么区别和联系
  7. freecplus框架-PostgreSQL数据库操作
  8. mysqli 语句和mysql语句一样吗_如何为动态sql语句准备mysqli语句
  9. 如何利用Printconfig dll:从 iPhone 到 NT AUTHORITY\SYSTEM 的真实案例
  10. PROTEL 99 使用之添加库
  11. Java OCR文字识别(Tess4J)
  12. linux系统是不是国产的,LINUX是什么系统,是国产软件吗
  13. docker desktop 阿里云镜像加速
  14. [机器学习]1模型评估与选择
  15. TiDB at 丰巢:尝鲜分布式数据库
  16. jieba 详细介绍
  17. Yield Guild Games 和 MOBLAND 达成合作
  18. 【英语:语法基础】B1.核心语法-名词与代词
  19. java大数据课程大纲(小牛学堂)
  20. 转帖【编码原则十日谈】

热门文章

  1. HMS Core线上Codelabs挑战赛第二期开始
  2. python 将一串数字形式的时间转换为标准时间格式
  3. 游戏建模工作内容是什么
  4. opencv基本操作二(读取视频流与保存视频、读取摄像头并保存视频)
  5. 抖音微信登录服务器繁忙,微信登录抖音失败解决方法介绍
  6. Linux下git操作(一)——git基本命令
  7. Netflix继续开源,更多猴子进入视野
  8. xv6 6.S081 Lab1: util
  9. SQLite WAL 机制探索
  10. 鹏业安装算量软件项目管理功能的操作步骤