在大型的应用中,为了提高数据库的水平伸缩性,对多个数据库实例进行管理,需要配置多数据源。在Spring框架被广泛运用的今天,可以很简单的运用Spring中的特性配置动态多数据。
1. 首先配置一个基于c3p0.ComboPooledDataSource的数据源A,数据源B.
daoContext.xml
<bean id="dataSourceA" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"> <property name="driverClass" value="${jdbc.driver}"></property> <property name="jdbcUrl" value="${jdbc.ur.al}?zeroDateTimeBehavior=convertToNull&characterEncoding=utf8"></property> <property name="user" value="${jdbc.user}"></property> <property name="password" value="${jdbc.password}"></property> <property name="minPoolSize" value="${jdbc.miniPoolSize}" /> <property name="maxPoolSize" value="${jdbc.maxPoolSize}"/> <property name="initialPoolSize" value="${jdbc.initialPoolSize}"/> <property name="maxIdleTime" value="${jdbc.maxIdleTime}"/> <property name="acquireIncrement" value="${jdbc.acquireIncrement}"/> <property name="acquireRetryAttempts" value="${jdbc.acquireRetryAttempts}"/> <property name="acquireRetryDelay" value="${jdbc.acquireRetryDelay}"/> <property name="idleConnectionTestPeriod" value="${jdbc.idleConnectionTestPeriod}"/> <property name="checkoutTimeout" value="${jdbc.checkoutTimeout}"/> </bean> <bean id="dataSourceB" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"> <property name="driverClass" value="${jdbc.driver}"></property> <property name="jdbcUrl" value="${jdbc.url.b}?zeroDateTimeBehavior=convertToNull&characterEncoding=utf8"></property> <property name="user" value="${jdbc.user}"></property> <property name="password" value="${jdbc.password}"></property> <property name="minPoolSize" value="${jdbc.miniPoolSize}" /> <property name="maxPoolSize" value="${jdbc.maxPoolSize}"/> <property name="initialPoolSize" value="${jdbc.initialPoolSize}"/> <property name="maxIdleTime" value="${jdbc.maxIdleTime}"/> <property name="acquireIncrement" value="${jdbc.acquireIncrement}"/> <property name="acquireRetryAttempts" value="${jdbc.acquireRetryAttempts}"/> <property name="acquireRetryDelay" value="${jdbc.acquireRetryDelay}"/> <property name="idleConnectionTestPeriod" value="${jdbc.idleConnectionTestPeriod}"/> <property name="checkoutTimeout" value="${jdbc.checkoutTimeout}"/> </bean>
3. 接着扩展一个Spring提供的AbstractRoutingDataSource,Override 其中的 determineCurrentLookupKey方法实现数据源的route.
package datasource; import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; public class DynamicDataSource extends AbstractRoutingDataSource{ @Override protected Object determineCurrentLookupKey() { return CustomerContextHolder.getCustomerType(); } }
而其中的CustomerContextHolder这是开发人员自己实现的一个封装了ThreadLocal类型的ContextHolder。
package datasource; public class CustomerContextHolder { public static final String DATA_SOURCE_A = "dataSourceA"; public static final String DATA_SOURCE_B = "dataSourceB"; private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>(); public static void setCustomerType(String customerType) { contextHolder.set(customerType); } public static String getCustomerType() { return contextHolder.get(); } public static void clearCustomerType() { contextHolder.remove(); } }
4.接下来就是在我们上面的daoContext.xml将这个DynamicDataSource Bean加入进去,同时配置targetDataSources的 Map映射。
<bean id="dynamicDataSource" class="datasource.DynamicDataSource" > <!-- 通过key-value的形式来关联数据源 --> <property name="targetDataSources"> <map key-type="java.lang.String"> <entry value-ref="dataSourceA" key="dataSourceA"></entry> <entry value-ref="dataSourceB" key="dataSourceB"></entry> </map> </property> <property name="defaultTargetDataSource" ref="dataSourceA" > </property> </bean>
5. 如何是用这个动态的多数据源呢? 其实很简单,因为我们的DynamicDataSource 是继承与AbstractRoutingDataSource,而AbstractRoutingDataSource又是继承于org.springframework.jdbc.datasource.AbstractDataSource,显然的AbstractDataSource实现了统一的DataSource接口,所以我们的DynamicDataSource 同样可以方便的当一个DataSource使用,下面拿Hibernate做例子:
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"> <!-- 可以看到和 普通的dataSource用法一样 --> <property name="dataSource" ref="dynamicDataSource" /> <property name="configLocations" value="classpath:hibernate.cfg.xml" /> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect">${hibernate.dialect}</prop> </props> </property> </bean>
可以看到我们用的仍然是一个sessionFactory,这样看来事务管理的配置也和以前一样。
<tx:annotation-driven transaction-manager="transactionManager"/> <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory" /> </bean>
DynamicDataSource Bean也在容器中了,现在剩下的就在程序中如何控制,选择某一个想要的数据源该怎么做:
//这样就将数据源动态的设置成了dataSourceB. CustomerContextHolder.setCustomerType(CustomerContextHolder.DATA_SOURCE_B);
或者使用AOP实现
package datasource; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; @Aspect public class DynamicDataSourceAspect { @Pointcut("execution (public service.impl..*.*(..))") public void serviceExecution(){} @Before("serviceExecution()") public void setDynamicDataSource(JoinPoint jp) { for(Object o : jp.getArgs()) { //处理具体的逻辑 ,根据具体的境况CustomerContextHolder.setCustomerType()选取DataSource } } }
6. 总结: 我们可以看到运用AbstractRoutingDataSource可以很好的实现多数据源的,而且以后扩展更多的数据源时也非常容易,只要增加数据源和修改DynamicDataSource Bean的targetDataSources 配置就好。关于选择某一个数据源,其实可以很好的用@Aspect在Service的入口加入一个切面@Pointcut,在@Before里判断JoinPoint的类容选定特定的数据源(例如更加JoinPoint的某个key来判断在设置CustomerContextHolder.setCustomerType)。 根究实际的应用来确定。个人看法: 以前有很多应用部署了writeDataSource和readDataSource和slaveDataBase的实现,但现在的大部分应用在构架上已经不太适合了,越来越注重和用户的交互性使得数据库间他同步变得日益复杂和难以维护,所以在架构系统时不妨考虑使用水平切割的方法来切割数据库,当然这种开发需要需要更多的时间分析业务领域,选取如何的配置数据源其实也是和业务息息相关的。
相关推荐
基于注解的Spring多数据源配置和使用 前一段时间研究了一下spring多数据源的配置和使用,为了后期从多个数据源拉取数据定时进行数据分析和报表统计做准备。由于之前做过的项目都是单数据源的,没有遇到这种场景,...
Spring多数据源配置_分布式数据 Tomcat服务器下的多数据源配置详情 一、环境及框架 Tomcat+spring+hibernate+jotm,还有就是struts、Oracle等 二、需求说明 系统里有2套不同网域的oracle数据库,之间的数据需要进行...
spring数据源配置
spring 动态多数据源配置代码,本项目是maven项目,里面有完成的配资好的spring多数据源代码和配置文件。
springboot多数据源配置
通过注解实现数据源的灵活切换
一个springboot的多数据配置,从mapper到controller完整的一个业务流程
主要介绍了spring多数据源配置实现方法,结合实例形式分析了spring多数据源配置相关操作技巧与使用注意事项,需要的朋友可以参考下
SSM(Spring+SpringMVC+MyBatis)多数据源配置框架,精简版
spring 配置多数据源
Spring Boot+Jpa多数据源配置Demo,可同时支持多种数据库,不同数据库,同时支持不同数据库的JdbcTemplate
搭建好eclipse版的ssm+maven+tk.mybatis+redis集成的demo。新手快速上手直接demo。完整高质量。整理不少时间分享没人赞好心疼吖吖。。。 或者直接看下面地址博客(由于太长所以博客不全) ...
阐述spring的数据源配置
项目中我们经常会遇到多数据源的问题,尤其是数据同步或定时任务等项目更是如此。本篇文章主要介绍了spring多数据源配置,有兴趣的可以了解一下。
通过简单的demo实现SpingBoot多数据源配置并动态切换多数据源
Spring Boot使用spring-data-jpa配置Mysql多数据源,可用版本
spring配置JNDI数据源
spring实现多数据源,可以在配置文件中添加