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. 获得当前数据库连接池可分配的最大链接数和当前数据库连接池中已经在使用中的链接,如果其中1个等于null,则返回null
  2. 如果最大链接数小于0,则直接返回-1
  3. 如果使用中的(激活)链接等于0L
  4. 通过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与数据源配置原理解析的更多相关文章

  1. SpringBoot2.x整合JDBC及初始化data.sql和schema.sql脚本

    今天在使用SpringBoot2.x版本整合JDBC时遇到了一些问题:由于我之前一直用SpringBoot1.5的版本,所以直接在yml里按照1.5的版本配置了属性,没想到2.x直接不能用了.首先是数 ...

  2. mysql之整合ssm多数据源配置

    一,基于SSM框架的多数据源配置 1.创建DynamicDataSourceHolder用于持有当前线程中使用的数据源标识 public class DynamicDataSourceHolder { ...

  3. 【Spring JDBC】数据源配置(二)

    一.Spring内置数据源 1. 创建Maven Project,修改pom.xml <properties> <!-- JDK版本 --> <java.version& ...

  4. spring boot(12)-数据源配置原理

    本篇讲的不仅是数据源配置,这也是spring boot实现自动配置的一部分.要理解数据源的配置原理,首先要理解第十篇tomcat连接池的配置 数据源配置源码 这里截取org.springframewo ...

  5. Spring Boot (14) 数据源配置原理

    数据源配置源码 这里截取org.springframework.boot.autoconfigure.jdbc.DataSourceConfiguration的部分源码,主要介绍Tomcat和Hika ...

  6. 4_7.springboot2.x嵌入式servlet容器自动配置原理

    概述 Spring Boot对所支持的Servlet Web服务器实现做了建模抽象: Servlet容器类型  WebServer模型接口 WebServer工厂实现类 Tomcat    Tomca ...

  7. SpringBoot整合Logback日志框架配置全解析

    目录 本篇要点 一.Logback日志框架介绍 二.SpringBoot与Logback 1.默认日志格式 2.控制台输出 3.文件输出 4.日志级别 5.日志组 6.自定义log配置 三.logba ...

  8. apache php配置 虚拟目录 和 虚拟主机 多域名配置 原理解析

    虚拟目录配置 就是说,我们放项目放在D盘,F盘,而不是默认的www文件夹下也可以访问.比如这里,我在 D:/PHP/work 放入的项目文件. 在httpd.conf加入: (位置一般是在 </ ...

  9. 4_9.springboot2.x之使用外置servlet容器原理解析

    问题概述 嵌入式Servlet容器: 应用打成可执行的jar 优点:简单.便携: **缺点:**默认不支持JSP.优化定制比较复杂(使用定制器[ServerProperties.自定义WebServe ...

随机推荐

  1. 阿里云HBase推出全新X-Pack服务 定义HBase云服务新标准

    2018年12月13日,第八届中国云计算标准和应用大会在京召开,会上阿里云HBase宣布推出全新X-Pack服务,支持SQL.时序.时空.图.全文检索能力.复杂分析,从处理到分析全栈式数据库,客户开箱 ...

  2. Aliyun 安装NPM 总是3.5.2 解决方案

    由于默认的命令 阿里云安装的 Node 是 8.x 版本 导致NPM 一直安装的都是 3.5.2 版本,死活升级不上去 最后手动安装指定版本解决 wget -qO- https://deb.nodes ...

  3. Apache Solr 远程命令+XXE执行漏洞(CVE-2017-12629)

    Apache Solr 最近有出了个漏洞预警,先复习一下之前的漏洞 命令执行 先创建一个listener,其中设置exe的值为我们想执行的命令,args的值是命令参数 POST /solr/demo/ ...

  4. MyBatis mappers元素标签及其属性、配置

    mappers:映射器,以最佳的方式是告诉 MyBatis 到哪里去找映射文件. <!-- 使用相对于类路径的资源引用,要满足一个条件:1.即映射文件只要放在类路径下,就可以根据相对路径找到,放 ...

  5. C在结构体里面使用共用体

    在做链表的时候我们设计每个节点都是一个结构体,每个节点的数据用一个共用体表示,每创建malloc一个结构体节点我们也要相应的malloc共用体并把它付进去. 这是定义: typedef union E ...

  6. 2018湘潭大学程序设计竞赛【D】

    题目链接:https://www.nowcoder.com/acm/contest/105/D 题意:就是数的fib表示方法.按权展开,又按二进制算出结果输出. 题解:贪心和数论吧.找到跟数最接近的f ...

  7. mysql连接数问题备份

    一. max_connections 这是是查询数据库当前设置的最大连接数 mysql> show variables like '%max_connections%';+----------- ...

  8. POST提交数据之---Content-Type的理解

    Content-Type是指http/https发送信息至服务器时的内容编码类型,contentType用于表明发送数据流的类型,服务器根据编码类型使用特定的解析方式,获取数据流中的数据. 在网络请求 ...

  9. 人脸识别-常用的数据库Face Databases From Other Research Groups

    Static/Videos Static Single/Multiple faces Single? Gray/Color Color Resolution Vaious Face pose Fron ...

  10. MySQL数据库之DML(数据操作语言)

    对表记录的增删改 1.MySQL之DML创建数据表user create table user( id int unsigned not null auto_increment primary key ...