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. 使用JavaMail发送邮件

    一.邮件的相关概念 邮件协议.主要包括: SMTP协议:Simple Mail Transfer Protocol,即简单邮件传输协议,用于发送电子邮件 POP3协议:Post Office Prot ...

  2. kettle中参数和变量的区别

    图一: 图二: 何时使用'?'何事使用${}应当根据情况: 在图二中使用的是${}因为此时没有"作为参数的字段",所以只能用el表达式直接获取其值,在图一中有"作为参数的 ...

  3. 使用串口线真机调试Linux内核

    一.环境 ubuntu 14.04 一台有串口的PC(编号PC1,被调试机器) 另一台PC通过USB转串口线连接PC1(编号PC2,发起调试命令的机器) 二.串口线配置及测试 安装cutecom US ...

  4. HTMl5的存储方式sessionStorage和localStorage详解

    html5中的Web Storage包括了两种存储方式:sessionStorage和localStorage.sessionStorage用于本地存储一个会话(session)中的数据,这些数据只有 ...

  5. lombok在IntelliJ IDEA下的使用

    lombok是一款可以精减java代码.提升开发人员生产效率的辅助工具,利用注解在编译期自动生成setter/getter/toString()/constructor之类的代码.代码越少,意味着出b ...

  6. Gulp 常用插件

    插件使用注意事项: 插件需要先 npm/cnpm install xx --save-dev gulp taskname,如果 task 已经设置成 default 的依赖,直接 gulp 即可 ta ...

  7. 网络切片在5G中的应用

    SDNLAB君 • 16-11-25 •1509 人围观 5G和网络切片 当5G被广泛提及的时候,网络切片是其中讨论最多的技术.像KT.SK Telecom.China Mobile.DT.KDDI. ...

  8. 关于PHP扩展开发(收藏)

    一.Linux shell命令: ls –lh    查看文件大小 du –a    查看文件及文件夹大小 -------------------------- nginx ------------- ...

  9. SimpleDateFormat转换时间格式

    SimpleDateFormat有两个常用的方法parse和format 其中SimpleDateFormat在创建时有一下集中格式可以选择 SimpleDateFormat sdf = new Si ...

  10. POJ 3422 Kaka's Matrix Travels

    Kaka's Matrix Travels Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 9567   Accepted:  ...