Spring 的动态数据源实现
1. 配置多个数据源
这里以两个c3p0数据库连接池的数据源作为实例。在Spring框架下使用c3p0的数据库需要加入c3p0-0.9.1.2.jar(现在最新的)这个支持包。这里以数据同步项目为例:
数据来源库的连接池数据源配置:
- <bean id="dataSourceFrom" class="com.mchange.v2.c3p0.ComboPooledDataSource">
- <property name="driverClass" value="${jdbc.driver}" />
- <property name="jdbcUrl" value="${jdbc.from.url}" />
- <property name="user" value="${jdbc.from.username}" />
- <property name="password" value="${jdbc.from.password}" />
- <property name="autoCommitOnClose" value="true" />
- <property name="checkoutTimeout" value="${cpool.checkoutTimeout}" />
- <property name="initialPoolSize" value="${cpool.minPoolSize}" />
- <property name="minPoolSize" value="${cpool.minPoolSize}" />
- <property name="maxPoolSize" value="${cpool.maxPoolSize}" />
- <property name="maxIdleTime" value="${cpool.maxIdleTime}" />
- <property name="acquireIncrement" value="${cpool.acquireIncrement}" />
- <property name="maxIdleTimeExcessConnections" value="${cpool.maxIdleTimeExcessConnections}" />
- </bean>
数据插入库的连接池数据源配置:
- <bean id="dataSourceTo" class="com.mchange.v2.c3p0.ComboPooledDataSource">
- <property name="driverClass" value="${jdbc.driver}" />
- <property name="jdbcUrl" value="${jdbc.to.url}" />
- <property name="user" value="${jdbc.to.username}" />
- <property name="password" value="${jdbc.to.password}" />
- <property name="autoCommitOnClose" value="true" />
- <property name="checkoutTimeout" value="${cpool.checkoutTimeout}" />
- <property name="initialPoolSize" value="${cpool.minPoolSize}" />
- <property name="minPoolSize" value="${cpool.minPoolSize}" />
- <property name="maxPoolSize" value="${cpool.maxPoolSize}" />
- <property name="maxIdleTime" value="${cpool.maxIdleTime}" />
- <property name="acquireIncrement" value="${cpool.acquireIncrement}" />
- <property name="maxIdleTimeExcessConnections" value="${cpool.maxIdleTimeExcessConnections}" />
- </bean>
注意:上面url,user,password等值是从classpath下的jdbc.properties中取得的。
通过Spring获取属性文件中的值,以供配置文件使用:
- <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
- <property name="locations" value="classpath:jdbc.properties" />
- </bean>
2. 扩展Spring的AbstractRoutingDataSource抽象类,实现动态数据源。
AbstractRoutingDataSource中的抽象方法determineCurrentLookupKey是实现数据源的route的核心.这里对该方法进行Override。
- public class DynamicDataSource extends AbstractRoutingDataSource{
- @Override
- protected Object determineCurrentLookupKey() {
- return DBContextHolder.getDBType();
- }
- }
上下文DbContextHolder为一线程安全的ThreadLocal,具体代码如下:
- public class DBContextHolder{
- public static final String DATA_SOURCE_FROM = "dataSourceFrom";
- public static final String DATA_SOURCE_TO = "dataSourceTo";
- private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();
- public static void setDBType(String dbType) {
- contextHolder.set(dbType);
- }
- public static String getDBType() {
- return contextHolder.get();
- }
- public static void clearDBType() {
- contextHolder.remove();
- }
- }
3.配置动态数据源
将DynamicDataSource Bean加入到Spring的上下文xml配置文件中去,同时配置DynamicDataSource的targetDataSources(多数据源目标)属性的Map映射。
- <bean id="dynamicDataSource" class="datasource.DynamicDataSource" >
- <!-- 通过key-value的形式来关联数据源 -->
- <property name="targetDataSources">
- <map>
- <entry value-ref="dataSourceFrom" key="dataSourceFrom"></entry>
- <entry value-ref="dataSourceTo" key="dataSourceTo"></entry>
- </map>
- </property>
- <property name="defaultTargetDataSource" ref="dataSourceFrom" />
- </bean>
4.使用动态数据源
例子中DynamicDataSource是继承与AbstractRoutingDataSource,而AbstractRoutingDataSource又是继承于org.springframework.jdbc.datasource.AbstractDataSource,AbstractDataSource实现了统一的DataSource接口,所以DynamicDataSource同样可以当一个DataSource使用。
在Spring的JdbcTemplate使用动态数据源的配置示例:
- <!-- JdbcTemplate使用动态数据源的配置 -->
- <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
- <property name="dataSource">
- <ref bean="dynamicDataSource" />
- </property>
- </bean>
- <!-- 对JdbcTemplate的应用封装类 -->
- <bean id="sqlBaseDAO" class="com.whty.dao.BaseDAOImpl">
- <property name="jdbcTemplate">
- <ref bean="jdbcTemplate" />
- </property>
- </bean>
在ORM框架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>
- </property>
- </bean>
5.事务管理
使用动态数据源的时候,可以看出和使用单数据源的时候相比,在使用配置上几乎没有差别,在进行性事务管理配置的时候也没有差别:
使用Spring的JdbcTemplate的事务管理配置示例:
- <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
- <property name="dataSource" ref="dynamicDataSource" />
- </bean>
- <bean id="sqlBaseDAOProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
- <property name="transactionManager" ref="transactionManager" />
- <property name="target" ref="sqlBaseDAO" />
- <property name="transactionAttributes">
- <props>
- <prop key="insert*">PROPAGATION_REQUIRED</prop>
- <prop key="*">PROPAGATION_REQUIRED,readOnly</prop>
- </props>
- </property>
- </bean>
使用Hibernate时的事务管理配置示例:
- <tx:annotation-driven transaction-manager="transactionManager"/>
- <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
- <property name="sessionFactory" ref="sessionFactory" />
- </bean>
6.动态数据源的管理控制
如何选择控制每个业务中需要的具体数据源,可是使用手动控制:
- ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
- BaseDAO dao = (BaseDAO) context.getBean("sqlBaseDAO", BaseDAOImpl.class);
- try {
- DBContextHolder.setCustomerType(DBContextHolder.DATA_SOURCE_FROM);
- System.err.println(dao.select("select count(*) sum from TEST t ").get(0).get("SUM"));
- DBContextHolder.setCustomerType(DBContextHolder.DATA_SOURCE_TO);
- System.err.println(dao.select("select count(*) sum from TEST t ").get(0).get("SUM"));
- } catch (Exception e) {
- e.printStackTrace();
- }
也可以采用AOP的控制方式:
- @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
- }
- }
- }
7.总结
通过扩展Spring的AbstractRoutingDataSource可以很好的实现多数据源的rout效果,而且对扩展更多的数据源有良好的伸缩性,只要增加数据源和修改DynamicDataSource的targetDataSources属性配置就好。在数据源选择控制上,可以采用手动控制(业务逻辑并不多的时候),也可以很好的用AOP的@Aspect在Service的入口加入一个切面@Pointcut,在@Before里判断JoinPoint的类容选定特定的数据源。
Spring 的动态数据源实现的更多相关文章
- Spring实现动态数据源,支持动态加入、删除和设置权重及读写分离
当项目慢慢变大,訪问量也慢慢变大的时候.就难免的要使用多个数据源和设置读写分离了. 在开题之前先说明下,由于项目多是使用Spring,因此下面说到某些操作可能会依赖于Spring. 在我经历过的项目中 ...
- Spring 实现动态数据源切换--转载 (AbstractRoutingDataSource)的使用
[参考]Spring(AbstractRoutingDataSource)实现动态数据源切换--转载 [参考] 利用Spring的AbstractRoutingDataSource解决多数据源的问题 ...
- Spring配置动态数据源-读写分离和多数据源
在现在互联网系统中,随着用户量的增长,单数据源通常无法满足系统的负载要求.因此为了解决用户量增长带来的压力,在数据库层面会采用读写分离技术和数据库拆分等技术.读写分离就是就是一个Master数据库,多 ...
- spring boot动态数据源方案
动态数据源 1.背景 动态数据源在实际的业务场景下需求很多,而且想要沟通多数据库确实需要封装这种工具,针对于bi工具可能涉及到从不同的业务库或者数据仓库中获取数据,动态数据源就更加有意义. 2.依赖 ...
- 使用Spring配置动态数据源实现读写分离
最近搭建的一个项目需要实现数据源的读写分离,在这里将代码进行分享,以供参考.关键词:DataSource .AbstractRoutingDataSource.AOP 首先是配置数据源 <!-- ...
- 43. Spring Boot动态数据源(多数据源自动切换)【从零开始学Spring Boot】
[视频&交流平台] àSpringBoot视频 http://study.163.com/course/introduction.htm?courseId=1004329008&utm ...
- Spring Boot 动态数据源(多数据源自己主动切换)
本文实现案例场景: 某系统除了须要从自己的主要数据库上读取和管理数据外.另一部分业务涉及到其它多个数据库,要求能够在不论什么方法上能够灵活指定详细要操作的数据库. 为了在开发中以最简单的方法使用,本文 ...
- (43). Spring Boot动态数据源(多数据源自动切换)【从零开始学Spring Boot】
在上一篇我们介绍了多数据源,但是我们会发现在实际中我们很少直接获取数据源对象进行操作,我们常用的是jdbcTemplate或者是jpa进行操作数据库.那么这一节我们将要介绍怎么进行多数据源动态切换.添 ...
- Spring Boot 动态数据源(Spring 注解数据源)
本文实现案例场景:某系统除了需要从自己的主要数据库上读取和管理数据外,还有一部分业务涉及到其他多个数据库,要求可以在任何方法上可以灵活指定具体要操作的数据库. 为了在开发中以最简单的方法使用,本文基于 ...
随机推荐
- 4-3 管理及IO重定向
1. 系统设定默认输出设备:标准输出(STDOUT,1) 系统设定默认输入设备:标准输入(STDIN,0) 系统设定默认错误设备:标准错误(STDERR,2) 2. 标准输入:键盘 标准输出和错误输出 ...
- Spring MVC之@RequestParam @RequestBody @RequestHeader 等详解
(转自:http://blog.csdn.net/walkerjong/article/details/7946109#) 引言: 接上一篇文章,对@RequestMapping进行地址映射讲解之后, ...
- 搭建基于PHP的www服务器
安装MySQL #!/bin/bash mount |grep "/dev/sr0" if [ "$?" != 0 ];then mount /dev/sr0 ...
- (转)也谈BIO | NIO | AIO (Java版)
原文地址: https://my.oschina.net/bluesky0leon/blog/132361 关于BIO | NIO | AIO的讨论一直存在,有时候也很容易让人混淆,就我的理解,给出一 ...
- 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 ...
- Linux进程环境
Linux下C程序都是main开始的,main函数的原型是: int main(int argc, char **argv) 其中argc是命令行参数的数目,argc是指向参数的各个指针所构成的数组. ...
- 使用jenkins配置.net mvc网站进行持续集成三
前两篇讲解了Jenkins的配置和VS远程发布,现在还有一个问题,VS项目远程发布的时候,配置的是覆盖所有文件重生成的,而通常类似于配置文件这种东西,在本地开发环境和测试环境是不一样的.所以我们通常需 ...
- 010商城项目:商品类目的选择——Dao,Service.Action层的分析
我们现在开始写商品类选择这个功能: 先看效果: 当我们点击"新增商品"---->"选择目录"然后从数据库中查出来数据并显示了. 我们分析数据库的那张表: ...
- PIC12F508/505/509/510/506/519/526/527单片机破解芯片解密方法!
IC芯片解密PIC12F508/505/509/510/506/519/526/527单片机破解 单片机芯片解密型号: PIC12F508解密 | PIC12F505解密 | PIC12F506解密 ...
- [LeetCode] Maximal Rectangle 最大矩形
Given a 2D binary matrix filled with 0's and 1's, find the largest rectangle containing all ones and ...