6_1.springboot2.x整合JDBC与数据源配置原理解析
1、引言
对于数据访问层,无论是SQL还是NOSQL,Spring Boot默认采用整合
Spring Data的方式进行统一处理,添加大量自动配置,屏蔽了很多设置。引入各种xxxTemplate,xxxRepository来简化我们对数据访问层的操作。对我们来说只需要进行简单的设置即可。
2、步骤
这里springboot版本是springboot2.18
1、引入starter –spring-boot-starter-jdbc
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring‐boot‐starter‐jdbc</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql‐connector‐java</artifactId>
<scope>runtime</scope>
</dependency
2、配置application.yml
spring:
datasource:
username: root
password: 123456
url: jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone = GMT
driver-class-name: com.mysql.cj.jdbc.Driver
注意:springboot2中默认数据源是Hikari,这里mysql驱动发生了更新,驱动名:
com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone = GMT
url要加入:serverTimezone=UTC否则会报错
3、测试
@RunWith(SpringRunner.class)
@SpringBootTest
public class Springboot06DataJdbcApplicationTests {
@Autowired
DataSource dataSource;
@Test
public void contextLoads() throws Exception {
System.out.println(dataSource.getClass());
Connection connection = dataSource. getConnection();
System.out.println(connection);
connection.close();
}
}
运行结果:
可以看出springboot2默认数据源使用的是hikariDatasorece
数据源的相关配置都是在
DataSourceProperties
3、原理解析
数据源配置解析
DataSourceConfiguration
作用:实际的数据源导入配置,包括
tomcat.jdbc.pool.DataSource、HikariDataSource、dbcp2.BasicDataSource
1、自定义数据源:
调用步骤:
DataSourceProperties
返回一个DataSourceBuilder对象,使用DataSourceBuilder创建数据源,利用反射创建响应type的数据源,并且绑定相关属性
DataSourceBuilder
2、数据源自动配置解析
DataSourceAutoConfiguration
@Configuration–> 配置类
@ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class })–> 在当前类路径下存在DataSource.class,EmbeddedDatabaseType.class 时生效
@EnableConfigurationProperties(DataSourceProperties.class) –> 可以通过spring.datasource.xxx 进行配置,同时导入了EnableConfigurationPropertiesImportSelector
@Import({ DataSourcePoolMetadataProvidersConfiguration.class, DataSourceInitializationConfiguration.class })
解析:DataSourcePoolMetadataProvidersConfiguration.class 自动装配每个数据源的元数据
DataSourcePoolMetadata的类图如下:
1.DataSourcePoolMetadata 接口–> 提供大多数数据库都提供的元数据的接口.定义如下:
public interface DataSourcePoolMetadata {
/**
* 返回当前数据库连接池的使用量,返回值在0至1之间(或者是-1,如果当前数据库连接池没有限制的话)
* <li>1 --> 该数据库连接池的链接数已达到最大数目</li>
* <li>0 --> 该数据库连接池的链接数</li>
* <li>-1 -->该数据库连接池的链接数没有限制 </li>
* </li>
* </ul>
* 还有可能返回null,如果当前的数据库链接池不提供必要的信息进行计算的话
*/
Float getUsage();
// 返回当前数据库连接池中已经在使用中的(激活)链接或者返回null,如果该信息不可用的话
Integer getActive();
// 返回当前数据库连接池可分配的最大链接数, 返回-1 意味着没有限制,返回null,意味着当前信息不可用
Integer getMax();
// 返回当前数据库连接池可分配的最小链接数, 返回null,意味着当前信息不可用
Integer getMin();
// 返回用来检查当前链接是否可以的sql,返回null-->当前信息不可用
String getValidationQuery();
}
2.AbstractDataSourcePoolMetadata –> DataSourcePoolMetadata 的抽象实现,实现了getUsage 方法,其它实现只需继承它实现其他的方法即可,代码如下:
public Float getUsage() {
// 1. 获得当前数据库连接池可分配的最大链接数和当前数据库连接池中已经在使用中的链接,如果其中1个等于null,则返回null
Integer maxSize = getMax();
Integer currentSize = getActive();
if (maxSize == null || currentSize == null) {
return null;
}
// 2. 如果最大链接数小于0,则直接返回-1
if (maxSize < 0) {
return -1F;
}
// 3. 如果使用中的(激活)链接等于0L
if (currentSize == 0) {
return 0F;
}
// 4. 通过currentSize/maxSize 进行计算
return (float) currentSize / (float) maxSize;
}
- 获得当前数据库连接池可分配的最大链接数和当前数据库连接池中已经在使用中的链接,如果其中1个等于null,则返回null
- 如果最大链接数小于0,则直接返回-1
- 如果使用中的(激活)链接等于0L
- 通过currentSize/maxSize 进行计算
同时,AbstractDataSourcePoolMetadata 持有了DataSource.通过构造器传入,代码如下:
private final T dataSource;
protected AbstractDataSourcePoolMetadata(T dataSource) {
this.dataSource = dataSource;
}
3.CommonsDbcp2DataSourcePoolMetadata–> 继承自AbstractDataSourcePoolMetadata,其持有的数据源类型为BasicDataSource.关于接口的实现只是简单的调用 dpcp中相关的api即可
public class CommonsDbcp2DataSourcePoolMetadata
extends AbstractDataSourcePoolMetadata<BasicDataSource> {
public CommonsDbcp2DataSourcePoolMetadata(BasicDataSource dataSource) {
super(dataSource);
}
@Override
public Integer getActive() {
return getDataSource().getNumActive();
}
@Override
public Integer getMax() {
return getDataSource().getMaxTotal();
}
@Override
public Integer getMin() {
return getDataSource().getMinIdle();
}
@Override
public String getValidationQuery() {
return getDataSource().getValidationQuery();
}
}
其自动装配是在CommonsDbcp2PoolDataSourceMetadataProviderConfiguration中声明的
/*
* Copyright 2012-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.jdbc.metadata;
import com.zaxxer.hikari.HikariDataSource;
import org.apache.commons.dbcp2.BasicDataSource;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.jdbc.DataSourceUnwrapper;
import org.springframework.boot.jdbc.metadata.CommonsDbcp2DataSourcePoolMetadata;
import org.springframework.boot.jdbc.metadata.DataSourcePoolMetadataProvider;
import org.springframework.boot.jdbc.metadata.HikariDataSourcePoolMetadata;
import org.springframework.boot.jdbc.metadata.TomcatDataSourcePoolMetadata;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* Register the {@link DataSourcePoolMetadataProvider} instances for the supported data
* sources.
*
* @author Stephane Nicoll
* @since 1.2.0
*/
@Configuration
public class DataSourcePoolMetadataProvidersConfiguration {
@Configuration
@ConditionalOnClass(org.apache.tomcat.jdbc.pool.DataSource.class)
static class TomcatDataSourcePoolMetadataProviderConfiguration {
@Bean
public DataSourcePoolMetadataProvider tomcatPoolDataSourceMetadataProvider() {
return (dataSource) -> {
org.apache.tomcat.jdbc.pool.DataSource tomcatDataSource = DataSourceUnwrapper.unwrap(dataSource,
org.apache.tomcat.jdbc.pool.DataSource.class);
if (tomcatDataSource != null) {
return new TomcatDataSourcePoolMetadata(tomcatDataSource);
}
return null;
};
}
}
@Configuration
@ConditionalOnClass(HikariDataSource.class)
static class HikariPoolDataSourceMetadataProviderConfiguration {
@Bean
public DataSourcePoolMetadataProvider hikariPoolDataSourceMetadataProvider() {
return (dataSource) -> {
HikariDataSource hikariDataSource = DataSourceUnwrapper.unwrap(dataSource, HikariDataSource.class);
if (hikariDataSource != null) {
return new HikariDataSourcePoolMetadata(hikariDataSource);
}
return null;
};
}
}
@Configuration
@ConditionalOnClass(BasicDataSource.class)
static class CommonsDbcp2PoolDataSourceMetadataProviderConfiguration {
@Bean
public DataSourcePoolMetadataProvider commonsDbcp2PoolDataSourceMetadataProvider() {
return (dataSource) -> {
BasicDataSource dbcpDataSource = DataSourceUnwrapper.unwrap(dataSource, BasicDataSource.class);
if (dbcpDataSource != null) {
return new CommonsDbcp2DataSourcePoolMetadata(dbcpDataSource);
}
return null;
};
}
}
}
- @Configuration –> 配置类
- @ConditionalOnClass(BasicDataSource.class) –> 在BeanFactory中如果存在BasicDataSource类型的bean时该配置生效,如果生效的话,则注册id为commonsDbcp2PoolDataSourceMetadataProvider,类型为DataSourcePoolMetadataProvider的bean
DataSourcePoolMetadataProvider
DataSourcePoolMetadataProvider的类图如下:
DataSourcePoolMetadataProvider接口–>根据DataSource 提供 DataSourcePoolMetadata.其只定义了1个方法,如下:
// 根据DataSource返回DataSourcePoolMetadata,或者返回null,如果给定的数据源没有对应的DataSourcePoolMetadata
DataSourcePoolMetadata getDataSourcePoolMetadata(DataSource dataSource);
2.DataSourcePoolMetadataProviders 实现了DataSourcePoolMetadataProvider接口,其内部持有DataSourcePoolMetadataProvider类型的List,在构造器中会注入在BeanFactory所有DataSourcePoolMetadataProvider类型的bean.代码如下:
会在DataSourcePoolMetadataProviders的构造器中注入在BeanFactory所有DataSourcePoolMetadataProvider类型的bean
public class CompositeDataSourcePoolMetadataProvider implements DataSourcePoolMetadataProvider {
private final List<DataSourcePoolMetadataProvider> providers;
/**
* Create a {@link CompositeDataSourcePoolMetadataProvider} instance with an initial
* collection of delegates to use.
* @param providers the data source pool metadata providers
*/
// 会在DataSourcePoolMetadataProviders的构造器中注入在BeanFactory所有DataSourcePoolMetadataProvider类型的bean
public CompositeDataSourcePoolMetadataProvider(Collection<? extends DataSourcePoolMetadataProvider> providers) {
this.providers = (providers != null) ? Collections.unmodifiableList(new ArrayList<>(providers))
: Collections.emptyList();
}
@Override
public DataSourcePoolMetadata getDataSourcePoolMetadata(DataSource dataSource) {
for (DataSourcePoolMetadataProvider provider : this.providers) {
DataSourcePoolMetadata metadata = provider.getDataSourcePoolMetadata(dataSource);
if (metadata != null) {
return metadata;
}
}
return null;
}
}
getDataSourcePoolMetadata 会依次遍历持有的providers,如果能根据给定的DataSource获得DataSourcePoolMetadata,则直接返回,否则返回null
解析:DataSourceInitializationConfiguration.class,数据源的初始化配置
DataSourceInitializerInvoker.class
作用:初始化的时候帮我们运行schene-*文件(建表),和data-*(数据)
afterPropertiesSet方法,初始化bean的时候执行,可以针对某个具体的bean进行配置。
@Override
public void afterPropertiesSet() {
DataSourceInitializer initializer = getDataSourceInitializer();
if (initializer != null) {
boolean schemaCreated = this.dataSourceInitializer.createSchema();
if (schemaCreated) {
initialize(initializer);
}
}
}
从容器中拿到数据源对象:
作用1:调用顺序->createSchema()->runScripts(),运行建表语句,
作用2:若建表语句创建则执行:initialize()->initSchema(),运行插入数据的语句;onApplicationEvent()当监听到某个事件也会执行方法
schema‐*.sql、data‐*.sql
默认规则:schema.sql,schema‐all.sql;
可以使用自定义位置:
schema:
‐ classpath:department.sql
源代码如图:
方法getScripts()得到文件的位置
注意:SpringBoot2通过sql脚本文件生成表时不成功时:
(1)在application配置文件指定执行sql(静态资源)的地方加上initialization-mode:always即可
(2)如果你配置文件没有指定执行文件的名称而是使用默认的schema.sql或者schema-all.sql的话就在配置文件中加上spring.datasource.initialization-mode=always
因为SpringBoot在启动时,只有检测到spring.datasource.initialization-mode=ALWAYS配置,然后再检测spring.datasource.schema,且配置的sql角本命令不为空,才会去执行schema和spring.datasource.data。因此需要在scheme.sql中随便写一句sql语句。所以在application.properties/application.yml文件中必须配置spring.datasource.initialization-mode=ALWAYS
操作数据库:
JdbcTemplateAutoConfiguration
@Configuration
@ConditionalOnClass({ DataSource.class, JdbcTemplate.class })
@ConditionalOnSingleCandidate(DataSource.class)
@AutoConfigureAfter(DataSourceAutoConfiguration.class)
@EnableConfigurationProperties(JdbcProperties.class)
public class JdbcTemplateAutoConfiguration {
@Configuration
static class JdbcTemplateConfiguration {
private final DataSource dataSource;
private final JdbcProperties properties;
JdbcTemplateConfiguration(DataSource dataSource, JdbcProperties properties) {
this.dataSource = dataSource;
this.properties = properties;
}
@Bean
@Primary
@ConditionalOnMissingBean(JdbcOperations.class)
public JdbcTemplate jdbcTemplate() {
JdbcTemplate jdbcTemplate = new JdbcTemplate(this.dataSource);
JdbcProperties.Template template = this.properties.getTemplate();
jdbcTemplate.setFetchSize(template.getFetchSize());
jdbcTemplate.setMaxRows(template.getMaxRows());
if (template.getQueryTimeout() != null) {
jdbcTemplate.setQueryTimeout((int) template.getQueryTimeout().getSeconds());
}
return jdbcTemplate;
}
}
@Configuration
@Import(JdbcTemplateConfiguration.class)
static class NamedParameterJdbcTemplateConfiguration {
@Bean
@Primary
@ConditionalOnSingleCandidate(JdbcTemplate.class)
@ConditionalOnMissingBean(NamedParameterJdbcOperations.class)
public NamedParameterJdbcTemplate namedParameterJdbcTemplate(JdbcTemplate jdbcTemplate) {
return new NamedParameterJdbcTemplate(jdbcTemplate);
}
}
}
自动配置了JdbcTemplate操作数据库
测试:
6_1.springboot2.x整合JDBC与数据源配置原理解析的更多相关文章
- SpringBoot2.x整合JDBC及初始化data.sql和schema.sql脚本
今天在使用SpringBoot2.x版本整合JDBC时遇到了一些问题:由于我之前一直用SpringBoot1.5的版本,所以直接在yml里按照1.5的版本配置了属性,没想到2.x直接不能用了.首先是数 ...
- mysql之整合ssm多数据源配置
一,基于SSM框架的多数据源配置 1.创建DynamicDataSourceHolder用于持有当前线程中使用的数据源标识 public class DynamicDataSourceHolder { ...
- 【Spring JDBC】数据源配置(二)
一.Spring内置数据源 1. 创建Maven Project,修改pom.xml <properties> <!-- JDK版本 --> <java.version& ...
- spring boot(12)-数据源配置原理
本篇讲的不仅是数据源配置,这也是spring boot实现自动配置的一部分.要理解数据源的配置原理,首先要理解第十篇tomcat连接池的配置 数据源配置源码 这里截取org.springframewo ...
- Spring Boot (14) 数据源配置原理
数据源配置源码 这里截取org.springframework.boot.autoconfigure.jdbc.DataSourceConfiguration的部分源码,主要介绍Tomcat和Hika ...
- 4_7.springboot2.x嵌入式servlet容器自动配置原理
概述 Spring Boot对所支持的Servlet Web服务器实现做了建模抽象: Servlet容器类型 WebServer模型接口 WebServer工厂实现类 Tomcat Tomca ...
- SpringBoot整合Logback日志框架配置全解析
目录 本篇要点 一.Logback日志框架介绍 二.SpringBoot与Logback 1.默认日志格式 2.控制台输出 3.文件输出 4.日志级别 5.日志组 6.自定义log配置 三.logba ...
- apache php配置 虚拟目录 和 虚拟主机 多域名配置 原理解析
虚拟目录配置 就是说,我们放项目放在D盘,F盘,而不是默认的www文件夹下也可以访问.比如这里,我在 D:/PHP/work 放入的项目文件. 在httpd.conf加入: (位置一般是在 </ ...
- 4_9.springboot2.x之使用外置servlet容器原理解析
问题概述 嵌入式Servlet容器: 应用打成可执行的jar 优点:简单.便携: **缺点:**默认不支持JSP.优化定制比较复杂(使用定制器[ServerProperties.自定义WebServe ...
随机推荐
- Perl 条件语句
Perl 条件语句 Perl 条件语句是通过一条或多条语句的执行结果(True或者False)来决定执行的代码块. 可以通过下图来简单了解条件语句的执行过程: 注意,数字 0, 字符串 '0' . & ...
- 《DNS攻击防范科普系列2》 -DNS服务器怎么防DDoS攻击
在上个系列<你的DNS服务真的安全么?>里我们介绍了DNS服务器常见的攻击场景,看完后,你是否对ddos攻击忧心重重?本节我们来告诉你,怎么破局!! 首先回顾一下DDoS攻击的原理.DDo ...
- NX二次开发-UFUN设置透明度UF_OBJ_set_translucency
NX9+VS2012 #include <uf.h> #include <uf_modl.h> #include <uf_obj.h> UF_initialize( ...
- NX二次开发-UF_MODL_ask_distance_tolerance获取建模的长度公差
NX9+VS2012 #include <uf.h> #include <uf_modl.h> #include <uf_ui.h> UF_initialize() ...
- 2018-2019-2-20175323 java实验三敏捷开发与XP实践
代码规范 安装alibaba插件 首先使用code栏里面的reformat code使代码的格式更加规范 再用编码规约扫描,alibaba把问题分为block/critical/major三个等级,出 ...
- CVE-2017-3248简单复现
我是这样操作的 目标跟windows在一个段,linux是另一个段的,我的虚拟机 windows主机上 `java -cp ysoserial.jar ysoserial.exploit.JRMPLi ...
- map、filter、forEach、reduce数组方法的封装
1.map方法的封装 Array.prototype.mapAlley = function(callback){ //获取调用mapAlley这个方法的数组 let arr = thi ...
- 转载:jQuery 获取屏幕高度、宽度
做手机Web开发做浏览器兼容用到了,所以在网上找了些汇总下. alert($(window).height()); //浏览器当前窗口可视区域高度 alert($(document).height() ...
- Day9 - 异步IO\数据库\队列\缓存
本节内容 Gevent协程 Select\Poll\Epoll异步IO与事件驱动 Python连接Mysql数据库操作 RabbitMQ队列 Redis\Memcached缓存 Paramiko SS ...
- [笔记]Android开发环境配置及HelloWorld程序
Android的开发须要下面四个工具: 1.JDK 2.Eclipse 3.Android SDK 4.ADT 具体功能: 1.JDK.JDK即Java Development Kit(Java开 ...