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. PostgreSQL-PL/pgSQL-cursor,loop

    将spam_keyword表word字段的字符全部拆分,只是利用过程语言完成循环的操作而已. create or replace function proc1() returns setof text ...

  2. 《HeadFirst SQL》笔记

    规范化 0 约束 1 原子性 2 第一范式 1NF 3 数据模式 4 依赖 5 联接查询 6 交叉联接(AKA 笛卡尔联接,叉积) 7 内联接 8 子查询 9 外联接 10 自联接 11 集合 12 ...

  3. 优化IPOL网站中基于DCT(离散余弦变换)的图像去噪算法(附源代码)。

    在您阅读本文前,先需要告诉你的是:即使是本文优化过的算法,DCT去噪的计算量依旧很大,请不要向这个算法提出实时运行的苛刻要求. 言归正传,在IPOL网站中有一篇基于DCT的图像去噪文章,具体的链接地址 ...

  4. [C]为什么发明指针?

    指针是C语言中广泛使用的一种数据类型. 运用指针编程是C语言最主要的风格之一.利用指针变量可以表示各种数据结构; 能很方便地使用数组和字符串; 并能象汇编语言一样处理内存地址,从而编出精练而高效的程序 ...

  5. 使用FastReport打印二维码

    简单介绍一下该功能所在的项目背景:C#语言编写的WPF客户端应用程序,在“结账”模块中,打印出的收款小票上需要显示一个二维码,服务生拿着小票去找顾客,顾客可以选择现金.银行卡等普通支付方式,也可以直接 ...

  6. kubernetes 文档

    kubernetes 官方文档:http://kubernetes.io/docs/ null

  7. Django session cookie 上传文件、详解

    session 在这里先说session 配置URL from django.conf.urls import patterns, include, url from django.contrib i ...

  8. static实现单例的隐患

    1. 前言 Java的单例有多种实现方式:单线程下的简单版本.无法在指令重排序下正常工作的Double-Check.static.内部类+static.枚举--.这篇文章要讨论的,是在使用static ...

  9. 冰冻三尺非一日之寒--web来了

    第十四章    html  css 1-1Html和CSS的关系学习web前端开发基础技术需要掌握:HTML.CSS.JavaScript语言.下面我们就来了解下这三门技术都是用来实现什么的:1. H ...

  10. Oracle数据库基础知识

    oracle数据库plsql developer   目录(?)[-] 一     SQL基础知识 创建删除数据库 创建删除修改表 添加修改删除列 oracle cascade用法 添加删除约束主键外 ...