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. NX二次开发-打开part对话框UF_UI_open_part

    这是UFUN帮助的官方例子 /****************************************************************************** Copyri ...

  2. 2018 – 2019 年前端 JavaScript 面试题

    JavaScript 基础问题 1.使以下代码正常运行: JavaScript 代码: const a = [1, 2, 3, 4, 5]; // Implement this a.multiply( ...

  3. spring-boot-configuration-processor

    spring默认使用yml中的配置,但有时候要用传统的xml或properties配置,就需要使用spring-boot-configuration-processor了 引入pom依赖 <de ...

  4. 【集合框架】JDK1.8源码分析之HashMap

    一.前言 在分析jdk1.8后的HashMap源码时,发现网上好多分析都是基于之前的jdk,而Java8的HashMap对之前做了较大的优化,其中最重要的一个优化就是桶中的元素不再唯一按照链表组合,也 ...

  5. sklearn提供的自带数据集

    sklearn 的数据集有好多个种 自带的小数据集(packaged dataset):sklearn.datasets.load_<name> 可在线下载的数据集(Downloaded ...

  6. 天道神诀---DHCP服务(下篇)

    DHCP作用域详解 subnet  定义一个作用域 netmask  定义作用域的掩码 range  允许发放的IP范围 option routers 指定网关地址 option domain-nam ...

  7. 5-MySQL高级-事务-回滚(3)

    回滚 为了演示效果,需要打开两个终端窗口,使用同一个数据库,操作同一张表 step1:连接 终端1 select * from goods_cates; step2:增加数据 终端2:开启事务,插入数 ...

  8. Docker学习の更改Docker的目录

    一.更改虚拟磁盘的目录 虚拟机的默认存储位置是C:\Users\Administrator\.docker\machine\machines ,后期docke镜像文件会不断增加,为了给系统盘减负,最好 ...

  9. mysql 触发器实现级联删除有外键的多张表

    2019-10-12 10:17:44 1.数据,建表时有可能会报错,只需要把前三行注释删掉就行 -- ---------------------------- -- Table structure ...

  10. Vagrant安装步骤

    Vagrant安装步骤 下载添加box镜像 vagrant box add base 远端的box地址或者本地的box文件名 建立box镜像关联 vagrant box add centos72 va ...