spring多数据源的配置-以及原理
spring多数据源的配置
创建一个类 继承 org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource
重写方法 determineCurrentLookupKey
package com.sky.lp.util;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;public class ExtendsAbstractRoutingDataSource extends AbstractRoutingDataSource{//使用ThreadLocal 保证线程安全private static final ThreadLocal<String> dataSourceKey = new InheritableThreadLocal<String>();public static void setDataSourceKey(String dataSource) {dataSourceKey.set(dataSource);}@Overrideprotected Object determineCurrentLookupKey() {return dataSourceKey.get();}
}
数据源配置
<!-- 定义数据源 使用 druid 包 --><bean id ="dataSource1" class= "com.alibaba.druid.pool.DruidDataSource" init-method= "init" destroy-method ="close"><property name ="name" value="druidOne" /><property name ="url" value= "jdbc:mysql://localhost:3306/littledemo" /><property name ="username" value="root" /><property name ="password" value= "laixu785^@#"></property ><property name ="driverClassName" value= "com.mysql.jdbc.Driver"></property ><property name ="initialSize" value="2" /><property name ="maxActive" value="10" /><property name ="minIdle" value="5" /><property name ="validationQuery" value= "SELECT COUNT(*) FROM DUAL" /><property name ="testWhileIdle" value="true" /><property name ="timeBetweenEvictionRunsMillis" value= "5000" /></bean ><!-- 定义数据源 使用 druid 包 --><bean id ="dataSource2" class= "com.alibaba.druid.pool.DruidDataSource" init-method= "init" destroy-method ="close"><property name ="name" value="druidTwo" /><property name ="url" value= "jdbc:mysql://localhost:3306/doubleo" /><property name ="username" value="root" /><property name ="password" value= "laixu785^@#"></property ><property name ="driverClassName" value= "com.mysql.jdbc.Driver"></property ><property name ="initialSize" value="2" /><property name ="maxActive" value="10" /><property name ="minIdle" value="5" /><property name ="validationQuery" value= "SELECT COUNT(*) FROM DUAL" /><property name ="testWhileIdle" value="true" /><property name ="timeBetweenEvictionRunsMillis" value= "5000" /></bean ><!-- 多数据源 --><bean id ="extendsAbstractRoutingDataSource" class= "com.sky.lp.util.ExtendsAbstractRoutingDataSource" >
<!-- 默认数据源 --><property name ="defaultTargetDataSource" ref= "dataSource2"/>
<!-- 不用的数据源对应不用的key值 --><property name ="targetDataSources"><map ><entry key ="dataSource1" value-ref= "dataSource1"/><entry key ="dataSource2" value-ref= "dataSource2"/></map ></property ></bean >spring jdbcTemplate 数据源的使用,
<bean id= "jdbcTemplate" class= "org.springframework.jdbc.core.JdbcTemplate" ><property name ="dataSource" ref= "extendsAbstractRoutingDataSource" />
</bean >
注意:
spring集成 ibatis 或者是 hibernate 或者其他的 ORM 框架,使用的数据源都是,extendsAbstractRoutingDataSource。
测试代码
public static void main(String[] args) {
ClassPathXmlApplicationContext appCtx = new ClassPathXmlApplicationContext("spring-servlet.xml");ExtendsAbstractRoutingDataSource myDataSource = appCtx.getBean("extendsAbstractRoutingDataSource", ExtendsAbstractRoutingDataSource.class);myDataSource.setDataSourceKey("dataSource1");JdbcTemplate jdbc = appCtx.getBean("jdbcTemplate", JdbcTemplate.class);List<?> list = jdbc.queryForList("select * from user");System.out.println(list);
}
spring多数据源工作原理(即多个数据源到底应该选择哪一下)
原理分析(这里以 spring 的 JdbcTemplate 为例子)
JdbcTemplate 中执行sql语句,是从 dataSource 中获取 数据库 Connection,通过Connection 执行sql 语句。
那么Connection是怎么获取到的呢,是通过
org.springframework.util.Assert.DataSourceUtils.getConnection(getDataSource()) 获取Connection的。
方法 getDataSource() 源码
public DataSource getDataSource() {return dataSource;
}
返回的dataSource,即配置 jdbcTemplate bean 的属性dataSource<property name ="dataSource" ref= "extendsAbstractRoutingDataSource" />
看一下org.springframework.util.Assert.DataSourceUtils.getConnection(getDataSource()) 的源码
public static Connection getConnection(DataSource dataSource) throws CannotGetJdbcConnectionException {try {return doGetConnection(dataSource);} catch (SQLException ex) {throw new CannotGetJdbcConnectionException("Could not get JDBC Connection", ex);}
}public static Connection doGetConnection(DataSource dataSource) throws SQLException {Assert.notNull(dataSource, "No DataSource specified");ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);if (conHolder != null && (conHolder.hasConnection() || conHolder.isSynchronizedWithTransaction()))conHolder.requested();if (!conHolder.hasConnection())logger.debug("Fetching resumed JDBC Connection from DataSource");conHolder.setConnection(dataSource.getConnection());return conHolder.getConnection();logger.debug("Fetching JDBC Connection from DataSource");Connection con = dataSource.getConnection();if (TransactionSynchronizationManager.isSynchronizationActive())logger.debug("Registering transaction synchronization for JDBC Connection");ConnectionHolder holderToUse = conHolder;if (holderToUse == null)holderToUse = new ConnectionHolder(con);elseholderToUse.setConnection(con);holderToUse.requested();TransactionSynchronizationManager.registerSynchronization( new ConnectionSynchronization(holderToUse, dataSource));holderToUse.setSynchronizedWithTransaction( true);if (holderToUse != conHolder)TransactionSynchronizationManager.bindResource(dataSource, holderToUse);return con;
}
解读上面的代码,最终的目的就是要从dataSource中获取数据库的Connection。而获取数据库的Connection必须调用dataSource的getConnection。
(即 javax.sql.DataSource的接口规定 getConnection() 方法 )。
所以,可以在从dataSource获取Connection的过程中做手脚。这就是
org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource 做的工作。
AbstractRoutingDataSource 继承 org.springframework.jdbc.datasource.AbstractDataSource,AbstractDataSource 实现 javax.sql.DataSource 接口。
下面看一下 AbstractRoutingDataSource 的方法 getConnection 的源码
public Connection getConnection() throws SQLException {return determineTargetDataSource().getConnection();
}protected DataSource determineTargetDataSource() {Assert.notNull(resolvedDataSources, "DataSource router not initialized");Object lookupKey = determineCurrentLookupKey();DataSource dataSource = (DataSource)resolvedDataSources.get(lookupKey);if(dataSource == null && (lenientFallback || lookupKey == null))dataSource = resolvedDefaultDataSource;if(dataSource == null)throw new IllegalStateException((new StringBuilder()).append("Cannot determine target DataSource for lookup key [").append(lookupKey).append("]").toString());return dataSource;
}
注意 源码中的方法 determineCurrentLookupKey(),我们自己定义的类 ExtendsAbstractRoutingDataSource 重写了 AbstractRoutingDataSource 中的 determineCurrentLookupKey 方法。
到这里大家应该明白了,spring的动态数据库切换是怎么实现的了。至于其他的地方,大家有不明白的就看看源码。
spring多数据源的配置-以及原理相关推荐
- 深入理解Spring Boot数据源与连接池原理
Create by yster@foxmail.com 2018-8-2 一:开始 在使用Spring Boot数据源之前,我们一般会导入相关依赖.其中数据源核心依赖就是spring‐boot‐s ...
- Spring Boot的自动配置的原理
Spring Boot在进行SpringApplication对象实例化时会加载META-INF/spring.factories文件,将该配置文件中的配置载入到Spring容器. 1.1 Mav ...
- [Spring Boot] 4. Spring Boot实现自动配置的原理
入口注解类@EnableAutoConfiguration @SpringBootApplication注解中包含了自动配置的入口注解: @Target(ElementType.TYPE) @Rete ...
- Spring, MyBatis 多数据源的配置和管理
同一个项目有时会涉及到多个数据库,也就是多数据源.多数据源又可以分为两种情况: 1)两个或多个数据库没有相关性,各自独立,其实这种可以作为两个项目来开发.比如在游戏开发中一个数据库是平台数据库,其它还 ...
- Spring Boot 自动配置的原理、核心注解以及利用自动配置实现了自定义 Starter 组件
本章内容 自定义属性快速入门 外化配置 自动配置 自定义创建 Starter 组件 摘录:读书是读完这些文字还要好好用心去想想,写书也一样,做任何事也一样 图 2 第二章目录结构图 第 2 章 Spr ...
- SpringBoot (八) :Spring Boot多数据源(JdbcTemplate)配置与使用
什么是JdbcTemplate 为了使 JDBC 更加易于使用,Spring 在 JDBCAPI 上定义了一个抽象层, 以此建立一个JDBC存取框架. 作为 SpringJDBC 框架的核心, JDB ...
- Spring多数据源配置和使用
Spring多数据源配置和使用 1.配置信息 <!--==============================bpt_mobdb数据库配置========================== ...
- spring(16)------spring的数据源配置
spring(16)------spring的数据源配置 在spring中,通过XML的形式实现数据源的注入有三种形式. 一.使用spring自带的DriverManagerDataSource 使用 ...
- 搭建eclipse版的ssm+maven+tk.mybatis+redis及mybatis+spring多数据源配置集成的demo
前言:我这里搭建好eclipse版的ssm+maven+tk.mybatis+redis及mybatis+spring多数据源配置集成的demo.新手快速上手直接看demo. 最后处提供完整高质量de ...
最新文章
- Spring MVC原理
- 华为视觉研究路线图:三大挑战,六项计划
- 如何在C++中动态建立二维数组
- 【网络流】 HDU 4183 Pahom on Water 拆点
- 转:[置顶] 从头到尾彻底理解KMP(2014年8月22日版)
- java集合的批量新建_java使用Arrays.asList快速创建List集合
- Tomcat虚拟目录的配置
- sap.ca.scfld.md.Startup.init('cus.crm.notes', this);
- 建立SQL Server警告和给操作员发送email通知
- CSS 文本缩进text-indent属性
- 经典算法题--求对策字符串的最大长度
- 安装nodejs插件并在sublime text 3上使用
- bzoj5138 [Usaco2017 Dec]Push a Box
- 解决Postman报错Could not send request
- 腾讯 IVWEB 团队:前端识别验证码思路分析
- 螺旋图形Linux,一个实例带你熟练使用UG中的螺旋线,新手必备!
- Android拦截黑名单(简易版)
- 克服低温磁场测量的挑战—高斯计
- checkra1n越狱错误79_苹果越狱工具 checkra1n 更新:支持 iOS 13.4.1
- html网页里如何竖着打字,搜狗输入法怎么设置为竖排显示 怎样把横向打字变成竖向...
热门文章
- 什么是 BeanDefinition?
- win7无法打开共享文件夹的文件
- 使用PXI设备做IC的开短路测试
- 黑衣人---走出软件作坊:三五个人十来条枪 如何成为开发正规军(三十四)
- R分数复现 R-precision评估指标定量 文本生成图像R分数定量实验全流程复现(R-precision)定量评价实验踩坑避坑流程
- telnet对应的端口不通,防火墙关闭了也不行
- java内部模型,13 张图拆解 Java 中的内存模型
- python 实现文件的批量压缩为.zip格式+.zip格式文件的解析
- 本机IP地址,ios的IP地址,www.ip138.com,
- 梦里Babel知多少(一)