1. 配置多个数据源

这里以两个c3p0数据库连接池的数据源作为实例。在Spring框架下使用c3p0的数据库需要加入c3p0-0.9.1.2.jar(现在最新的)这个支持包。这里以数据同步项目为例:

数据来源库的连接池数据源配置:

  1. <bean id="dataSourceFrom" class="com.mchange.v2.c3p0.ComboPooledDataSource">
  2. <property name="driverClass" value="${jdbc.driver}" />
  3. <property name="jdbcUrl" value="${jdbc.from.url}" />
  4. <property name="user" value="${jdbc.from.username}" />
  5. <property name="password" value="${jdbc.from.password}" />
  6. <property name="autoCommitOnClose" value="true" />
  7. <property name="checkoutTimeout" value="${cpool.checkoutTimeout}" />
  8. <property name="initialPoolSize" value="${cpool.minPoolSize}" />
  9. <property name="minPoolSize" value="${cpool.minPoolSize}" />
  10. <property name="maxPoolSize" value="${cpool.maxPoolSize}" />
  11. <property name="maxIdleTime" value="${cpool.maxIdleTime}" />
  12. <property name="acquireIncrement" value="${cpool.acquireIncrement}" />
  13. <property name="maxIdleTimeExcessConnections" value="${cpool.maxIdleTimeExcessConnections}" />
  14. </bean>

数据插入库的连接池数据源配置:

  1. <bean id="dataSourceTo" class="com.mchange.v2.c3p0.ComboPooledDataSource">
  2. <property name="driverClass" value="${jdbc.driver}" />
  3. <property name="jdbcUrl" value="${jdbc.to.url}" />
  4. <property name="user" value="${jdbc.to.username}" />
  5. <property name="password" value="${jdbc.to.password}" />
  6. <property name="autoCommitOnClose" value="true" />
  7. <property name="checkoutTimeout" value="${cpool.checkoutTimeout}" />
  8. <property name="initialPoolSize" value="${cpool.minPoolSize}" />
  9. <property name="minPoolSize" value="${cpool.minPoolSize}" />
  10. <property name="maxPoolSize" value="${cpool.maxPoolSize}" />
  11. <property name="maxIdleTime" value="${cpool.maxIdleTime}" />
  12. <property name="acquireIncrement" value="${cpool.acquireIncrement}" />
  13. <property name="maxIdleTimeExcessConnections" value="${cpool.maxIdleTimeExcessConnections}" />
  14. </bean>

注意:上面url,user,password等值是从classpath下的jdbc.properties中取得的。

通过Spring获取属性文件中的值,以供配置文件使用:

  1. <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
  2. <property name="locations" value="classpath:jdbc.properties" />
  3. </bean>

     2. 扩展Spring的AbstractRoutingDataSource抽象类,实现动态数据源。

AbstractRoutingDataSource中的抽象方法determineCurrentLookupKey是实现数据源的route的核心.这里对该方法进行Override。

  1. public class DynamicDataSource extends AbstractRoutingDataSource{
  2. @Override
  3. protected Object determineCurrentLookupKey() {
  4. return DBContextHolder.getDBType();
  5. }
  6. }

上下文DbContextHolder为一线程安全的ThreadLocal,具体代码如下:

  1. public class DBContextHolder{
  2. public static final String DATA_SOURCE_FROM = "dataSourceFrom";
  3. public static final String DATA_SOURCE_TO = "dataSourceTo";
  4. private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();
  5. public static void setDBType(String dbType) {
  6. contextHolder.set(dbType);
  7. }
  8. public static String getDBType() {
  9. return contextHolder.get();
  10. }
  11. public static void clearDBType() {
  12. contextHolder.remove();
  13. }
  14. }

   3.配置动态数据源

将DynamicDataSource Bean加入到Spring的上下文xml配置文件中去,同时配置DynamicDataSource的targetDataSources(多数据源目标)属性的Map映射。

  1. <bean id="dynamicDataSource" class="datasource.DynamicDataSource" >
  2. <!-- 通过key-value的形式来关联数据源 -->
  3. <property name="targetDataSources">
  4. <map>
  5. <entry value-ref="dataSourceFrom" key="dataSourceFrom"></entry>
  6. <entry value-ref="dataSourceTo" key="dataSourceTo"></entry>
  7. </map>
  8. </property>
  9. <property name="defaultTargetDataSource" ref="dataSourceFrom" />
  10. </bean>

   4.使用动态数据源

例子中DynamicDataSource是继承与AbstractRoutingDataSource,而AbstractRoutingDataSource又是继承于org.springframework.jdbc.datasource.AbstractDataSource,AbstractDataSource实现了统一的DataSource接口,所以DynamicDataSource同样可以当一个DataSource使用。

在Spring的JdbcTemplate使用动态数据源的配置示例:

  1. <!-- JdbcTemplate使用动态数据源的配置 -->
  2. <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
  3. <property name="dataSource">
  4. <ref bean="dynamicDataSource" />
  5. </property>
  6. </bean>
  7. <!-- 对JdbcTemplate的应用封装类 -->
  8. <bean id="sqlBaseDAO" class="com.whty.dao.BaseDAOImpl">
  9. <property name="jdbcTemplate">
  10. <ref bean="jdbcTemplate" />
  11. </property>
  12. </bean>

在ORM框架Hibernate中的使用配置示例:

  1. <bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
  2. <!-- 和普通的dataSource用法一样 -->
  3. <property name="dataSource" ref="dynamicDataSource" />
  4. <property name="configLocations" value="classpath:hibernate.cfg.xml" />
  5. <property name="hibernateProperties">
  6. <props>
  7. <prop key="hibernate.dialect">${hibernate.dialect}</prop>
  8. </property>
  9. </bean>

5.事务管理

使用动态数据源的时候,可以看出和使用单数据源的时候相比,在使用配置上几乎没有差别,在进行性事务管理配置的时候也没有差别:

使用Spring的JdbcTemplate的事务管理配置示例:

  1. <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
  2. <property name="dataSource" ref="dynamicDataSource" />
  3. </bean>
  4. <bean id="sqlBaseDAOProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
  5. <property name="transactionManager" ref="transactionManager" />
  6. <property name="target" ref="sqlBaseDAO" />
  7. <property name="transactionAttributes">
  8. <props>
  9. <prop key="insert*">PROPAGATION_REQUIRED</prop>
  10. <prop key="*">PROPAGATION_REQUIRED,readOnly</prop>
  11. </props>
  12. </property>
  13. </bean>

使用Hibernate时的事务管理配置示例:

  1. <tx:annotation-driven transaction-manager="transactionManager"/>
  2. <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
  3. <property name="sessionFactory" ref="sessionFactory" />
  4. </bean>

 6.动态数据源的管理控制

如何选择控制每个业务中需要的具体数据源,可是使用手动控制:

  1. ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
  2. BaseDAO dao = (BaseDAO) context.getBean("sqlBaseDAO", BaseDAOImpl.class);
  3. try {
  4. DBContextHolder.setCustomerType(DBContextHolder.DATA_SOURCE_FROM);
  5. System.err.println(dao.select("select count(*) sum from TEST t ").get(0).get("SUM"));
  6. DBContextHolder.setCustomerType(DBContextHolder.DATA_SOURCE_TO);
  7. System.err.println(dao.select("select count(*) sum from TEST t ").get(0).get("SUM"));
  8. } catch (Exception e) {
  9. e.printStackTrace();
  10. }

也可以采用AOP的控制方式:

  1. @Aspect
  2. public class DynamicDataSourceAspect {
  3. @Pointcut("execution (public service.impl..*.*(..))")
  4. public void serviceExecution(){}
  5. @Before("serviceExecution()")
  6. public void setDynamicDataSource(JoinPoint jp) {
  7. for(Object o : jp.getArgs()) {
  8. //处理具体的逻辑 ,根据具体的境况CustomerContextHolder.setCustomerType()选取DataSource
  9. }
  10. }
  11. }

7.总结

通过扩展Spring的AbstractRoutingDataSource可以很好的实现多数据源的rout效果,而且对扩展更多的数据源有良好的伸缩性,只要增加数据源和修改DynamicDataSource的targetDataSources属性配置就好。在数据源选择控制上,可以采用手动控制(业务逻辑并不多的时候),也可以很好的用AOP的@Aspect在Service的入口加入一个切面@Pointcut,在@Before里判断JoinPoint的类容选定特定的数据源。

Spring 的动态数据源实现的更多相关文章

  1. Spring实现动态数据源,支持动态加入、删除和设置权重及读写分离

    当项目慢慢变大,訪问量也慢慢变大的时候.就难免的要使用多个数据源和设置读写分离了. 在开题之前先说明下,由于项目多是使用Spring,因此下面说到某些操作可能会依赖于Spring. 在我经历过的项目中 ...

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

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

  3. Spring配置动态数据源-读写分离和多数据源

    在现在互联网系统中,随着用户量的增长,单数据源通常无法满足系统的负载要求.因此为了解决用户量增长带来的压力,在数据库层面会采用读写分离技术和数据库拆分等技术.读写分离就是就是一个Master数据库,多 ...

  4. spring boot动态数据源方案

    动态数据源 1.背景 动态数据源在实际的业务场景下需求很多,而且想要沟通多数据库确实需要封装这种工具,针对于bi工具可能涉及到从不同的业务库或者数据仓库中获取数据,动态数据源就更加有意义. 2.依赖 ...

  5. 使用Spring配置动态数据源实现读写分离

    最近搭建的一个项目需要实现数据源的读写分离,在这里将代码进行分享,以供参考.关键词:DataSource .AbstractRoutingDataSource.AOP 首先是配置数据源 <!-- ...

  6. 43. Spring Boot动态数据源(多数据源自动切换)【从零开始学Spring Boot】

    [视频&交流平台] àSpringBoot视频 http://study.163.com/course/introduction.htm?courseId=1004329008&utm ...

  7. Spring Boot 动态数据源(多数据源自己主动切换)

    本文实现案例场景: 某系统除了须要从自己的主要数据库上读取和管理数据外.另一部分业务涉及到其它多个数据库,要求能够在不论什么方法上能够灵活指定详细要操作的数据库. 为了在开发中以最简单的方法使用,本文 ...

  8. (43). Spring Boot动态数据源(多数据源自动切换)【从零开始学Spring Boot】

    在上一篇我们介绍了多数据源,但是我们会发现在实际中我们很少直接获取数据源对象进行操作,我们常用的是jdbcTemplate或者是jpa进行操作数据库.那么这一节我们将要介绍怎么进行多数据源动态切换.添 ...

  9. Spring Boot 动态数据源(Spring 注解数据源)

    本文实现案例场景:某系统除了需要从自己的主要数据库上读取和管理数据外,还有一部分业务涉及到其他多个数据库,要求可以在任何方法上可以灵活指定具体要操作的数据库. 为了在开发中以最简单的方法使用,本文基于 ...

随机推荐

  1. java.util.ConcurrentModificationException 解决办法(转载)

    今天在项目的中有一个需求,需要在一个Set类型的集合中删除满足条件的对象,这时想当然地想到直接调用Set的remove(Object o)方法将指定的对象删除即可,测试代码:   public cla ...

  2. BZOJ 2588: Spoj 10628. Count on a tree [树上主席树]

    2588: Spoj 10628. Count on a tree Time Limit: 12 Sec  Memory Limit: 128 MBSubmit: 5217  Solved: 1233 ...

  3. javamail文件上传

    //创建entity package cn.bdqn.pojo; import java.io.File; public class Mail { private String from; priva ...

  4. $x^2+y^2=c^2$

    $x^2+y^2=c^2$ 每一个实数都能用有理数去逼近到任意精确的程度,这就是有理数的稠密性.The rational points are dense on the number axis. 每一 ...

  5. virtualBox安装Centos7之后

    之前用vmware装虚拟机的时候,直接配置好网卡就可以ping通,可以用ssh登录,然后配置yum源,万事大吉. 但是virtualBox配置却有不同,需要按下面的方法配置: 选中虚拟机->设置 ...

  6. [LeetCode] Trapping Rain Water II 收集雨水之二

    Given an m x n matrix of positive integers representing the height of each unit cell in a 2D elevati ...

  7. 【三石jQuery视频教程】01.图片循环展示

    视频地址:http://v.qq.com/page/e/5/t/e0149n5he5t.html 大家好,欢迎来到[三石jQuery视频教程],我是您的老朋友 - 三生石上. 今天,我们要通过基本的H ...

  8. 两年来的core折腾之路几点总结,附上nginx启用http2拿来即用的配置

    序:一年多没更新博客园的内容了,core已经发生了翻天覆地的变化,想起2014年这时候,我就开始了从当时还叫k的那套preview都不如的vnext搭建这套系统,陆陆续续它每一次升级,我也相应地折腾, ...

  9. Java反射机制

    Java反射机制 一:什么事反射机制 简单地说,就是程序运行时能够通过反射的到类的所有信息,只需要获得类名,方法名,属性名. 二:为什么要用反射:     静态编译:在编译时确定类型,绑定对象,即通过 ...

  10. NIO服务器

    导语 NIO的出现是为服务器端编程而设计的.它的作用就是能够让一个线程为多个连接服务.NIO中的API都是非阻塞模式的,这样可以在服务器端采用异步的方式来处理多个请求.NIO中有两个重要的东西就是通道 ...