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. 4-3 管理及IO重定向

    1. 系统设定默认输出设备:标准输出(STDOUT,1) 系统设定默认输入设备:标准输入(STDIN,0) 系统设定默认错误设备:标准错误(STDERR,2) 2. 标准输入:键盘 标准输出和错误输出 ...

  2. Spring MVC之@RequestParam @RequestBody @RequestHeader 等详解

    (转自:http://blog.csdn.net/walkerjong/article/details/7946109#) 引言: 接上一篇文章,对@RequestMapping进行地址映射讲解之后, ...

  3. 搭建基于PHP的www服务器

    安装MySQL #!/bin/bash mount |grep "/dev/sr0" if [ "$?" != 0 ];then mount /dev/sr0 ...

  4. (转)也谈BIO | NIO | AIO (Java版)

    原文地址: https://my.oschina.net/bluesky0leon/blog/132361 关于BIO | NIO | AIO的讨论一直存在,有时候也很容易让人混淆,就我的理解,给出一 ...

  5. Ural 1225. Flags 斐波那契DP

    1225. Flags Time limit: 1.0 secondMemory limit: 64 MB On the Day of the Flag of Russia a shop-owner ...

  6. Linux进程环境

    Linux下C程序都是main开始的,main函数的原型是: int main(int argc, char **argv) 其中argc是命令行参数的数目,argc是指向参数的各个指针所构成的数组. ...

  7. 使用jenkins配置.net mvc网站进行持续集成三

    前两篇讲解了Jenkins的配置和VS远程发布,现在还有一个问题,VS项目远程发布的时候,配置的是覆盖所有文件重生成的,而通常类似于配置文件这种东西,在本地开发环境和测试环境是不一样的.所以我们通常需 ...

  8. 010商城项目:商品类目的选择——Dao,Service.Action层的分析

    我们现在开始写商品类选择这个功能: 先看效果: 当我们点击"新增商品"---->"选择目录"然后从数据库中查出来数据并显示了. 我们分析数据库的那张表: ...

  9. PIC12F508/505/509/510/506/519/526/527单片机破解芯片解密方法!

    IC芯片解密PIC12F508/505/509/510/506/519/526/527单片机破解 单片机芯片解密型号: PIC12F508解密 | PIC12F505解密 | PIC12F506解密  ...

  10. [LeetCode] Maximal Rectangle 最大矩形

    Given a 2D binary matrix filled with 0's and 1's, find the largest rectangle containing all ones and ...