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. Redis学习笔记~Redis事务机制与Lind.DDD.Repositories.Redis事务机制的实现

    回到目录 Redis本身支持事务,这就是SQL数据库有Transaction一样,而Redis的驱动也支持事务,这在ServiceStack.Redis就有所体现,它也是目前最受业界认可的Redis ...

  2. Oracle学习笔记十二 子程序(存储过程、自定函数)和程序包

    子程序 子程序:命名的 PL/SQL 块,编译并存储在数据库中.   子程序的各个部分: 1.声明部分 2.可执行部分 3.异常处理部分(可选) 子程序的分类: 1.过程 - 执行某些操作 2.函数 ...

  3. .NET和JAVA中BYTE的区别以及JAVA中“DES/CBC/PKCS5PADDING” 加密解密在.NET中的实现

    场景:java 作为客户端调用已有的一个.net写的server的webservice,输入string,返回字节数组. 问题:返回的值不是自己想要的,跟.net客户端直接调用总是有差距 分析:平台不 ...

  4. Apache服务停止:信号灯超时时间已到,指定的网络名不再可用

    环境说明:Apache2.4.10,Windows Server 2008 R2 问题说明: apache服务用于下载文件,但是在运行一段时间后,突然挂了. 其错误提示如下所示: [error] (7 ...

  5. mysql语句查询练习

                                                                     1.创建students表mysql> create table ...

  6. python3条件控制if

    Python条件语句是通过一条或多条语句的执行结果(为真或假)来决定执行哪部分代码. if语句 if语句的一般形式如下: if 条件1: 语句1 elif 条件2: 语句2 else: 语句3 其意思 ...

  7. [LeetCode] Find Median from Data Stream 找出数据流的中位数

    Median is the middle value in an ordered integer list. If the size of the list is even, there is no ...

  8. insmod模块的几种常见错误

    1. 与内核版本不一致 嵌入式开发时,模块编译时需要制定内核的路径,内核的版本信息会加入到模块文件中,如果目标板上运行的内核与模块中包含的内核版本对不上,加载就会出错,报如下错误:  insmod i ...

  9. curl的登录总结

    demo1 <?php $curl=curl_init('http://www.baidu.com'); curl_exec($curl); curl_close($curl); ?> c ...

  10. Python后台分页删除编辑查询

    「POST 数据」通常指 POST 时 body 中的数据.而 QueryString (URL)中也有可以带参数(通常是 GET 时的参数).如果 POST 时同时存在 QueryString 和 ...