配置数据源

在介绍数据源时,离不开配置数据源,因此我们就从配置数据源入手。在数据源的配置中,又存在默认数据源与第三方数据源,同时需要考虑连接池的使用,本节就将介绍这些知识。

默认数据源

首先,引入依赖,代码如下所示。

<!--JPA引入-->
<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

在引入 spring-boot-starter-data-jpa 之后,会设置默认数据源,这里的数据库主要有 3 个,分别是 HSQL、H2、DERBY。在下面的代码中可以了解。

package org.springframework.jdbc.datasource.embedded;
public enum EmbeddedDatabaseType {
   HSQL,
   H2,
   DERBY;
   private EmbeddedDatabaseType() {
   }
}

这 3 个内置的数据库都是常见的内存数据库,在不需要外接数据库的情况下,就能运行 Spring Boot 程序。

内存数据库不需要配置,但是,在实际场景中需要使用不同的数据库。这明显不符合实际场景应用,因此我们需要使用其他商用数据库。

自定义数据源

在 Spring Boot 中,数据库在默认连接的时候,可以使用 DataSource 连接池自动配置。在 Spring Boot 中,有 3 种连接池可以使用,目前使用的版本是 Spring Boot2,与 Spring Boot1 的默认连接池策略有所不同,主要通过下面的方式进行配置。

  1. 如果存在 HikariCP 能够使用,则使用 HikariCP。

  2. 在使用 Tomcat 时,会优先使用 Tomcat 自带的数据库连接池。

  3. 如果可以使用 DBCP2,则推荐使用 DBCP2。

为什么选择HikariCP

在 Spring Boot1 中,使用 Tomcat 自带的连接池,为什么在最新的 Spring Boot2 中则换成 HikariCP?我们都知道,HikariCP 是数据库连接池的一个 “后起之秀”,可以完美地取代其他连接池,是一个高性能的 JDBC 连接池。

BoneCP 是一个速度比较快的连接池,后来被废弃,而 HikariCP 基于 BoneCP 做了不少改进和优化,因此速度很快。并且,HikariCP 稳定性也很好。

在可靠性方面,遇到连接中断,HikariCP 的处理方式是比较合理的。除此之外还有一个因素,HikariCP 代码量很小,只有 130KB,一般存在更少的漏洞。

使用默认的连接池进行配置

首先,选择使用 MySQL 的数据库作为数据源,依赖如下所示。

<!--mysql-->
<dependency>
   <groupId>mysql</groupId>
   <artifactId>mysql-connector-java</artifactId>
</dependency>

在这里,先引入 spring-boot-starter-jdbc,依赖如下所示。

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>

现在,开始在 application.properties 中进行数据库的配置,配置项如下所示。

spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3308/test
spring.datasource.username=root
spring.datasource.password=123456

在上面的代码中,我们还是写了 spring.datasource.driver-class-name 配置项。其实在 Spring Boot 中,如果不写也不会报错,通常会尽量推断出来,但为了使代码更清晰,在这里全部写了出来。

在写测试类代码之前,我们先看 dataSource 结构情况,如图6.1所示。

image 2024 03 31 17 25 46 143
Figure 1. 图6.1 dataSource结构

在上图中,新建一个 dataSource 包,存放数据源的测试程序。现在数据库已配置好,我们开始进行测试,测试程序在 test 包下,代码如下所示。

package com.springBoot.dataSource.test;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.PropertySource;
import org.springframework.test.context.junit4.SpringRunner;
import javax.sql.DataSource;
import java.sql.SQLException;
@SpringBootApplication
@SpringBootTest
//@PropertySource(value = "classpath:application.properties",ignore ResourceNotFound = true)
@RunWith(SpringRunner.class)
public class ShowDataSource {
   @Autowired
   ApplicationContext applicationContext;
   @Autowired
   DataSourceProperties dataSourceProperties;
   @Test
   public void testDataSource() throws SQLException {
      DataSource dataSource=applicationContext.getBean(DataSource. class);
      System.out.println(dataSource);
      System.out.println(dataSource.getClass().getName());
      System.out.println(dataSourceProperties.getUrl());
   }
}

在上面的代码中,因为是在根目录下写 Spring Boot 的启动类,如果不写 @SpringBootApplication,这里启动 Test 会有下面的报错信息。

java.lang.IllegalStateException: Unable to find a @SpringBootConfiguration, you need to use @Context

在上面的程序中,依赖注入了 DataSourceProperties,它就是以 spring.datasource 作为前缀,然后通过名字直接映射出对象的属性,同时还包含了一些默认值。下面是部分源码。

package org.springframework.boot.autoconfigure.jdbc;
@ConfigurationProperties(prefix = "spring.datasource")
public class DataSourceProperties implements BeanClassLoaderAware, InitializingBean {
   private ClassLoader classLoader;
   private String name;
……
}

测试类代码写完,运行程序,最终的结果如下所示。

HikariDataSource (null)
com.zaxxer.hikari.HikariDataSource
jdbc:mysql://localhost:3308/test

从这里可以看到,默认使用的数据库连接池是 HikariCP。

注意:在 pom 文件中,我们没有引入下面的依赖。

<dependency>
   <groupId>com.zaxxer</groupId>
   <artifactId>HikariCP</artifactId>
</dependency>

因为,在加入 spring-boot-starter-jdbc 时,已经默认引入这个依赖,不需要单独添加。

使用自定义连接池进行配置

如果不想使用默认的 HikariCP,而想使用 DBCP2,首先需要添加 DBCP2 的依赖,这里依赖必须添加,不然在读取 datasource 类型时会报错。DBCP2 的依赖如下所示。

<dependency>
   <groupId>org.apache.commons</groupId>
   <artifactId>commons-dbcp2</artifactId>
</dependency>

配置 DBCP2 的数据源,下面是 application.properties 中的配置。

#spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3308/test
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.type=org.apache.commons.dbcp2.BasicDataSource
spring.datasource.dbcp2.max-idle=10
spring.datasource.dbcp2.max-total=50
spring.datasource.dbcp2.max-wait-millis=100000
spring.datasource.dbcp2.initial-size=5
spring.datasource.dbcp2.connection-properties=characterEncoding=utf8

在这里可能会注意到,这里注释掉 driver-class-name,主要是为了说明没有这一行代码仍然不会报错。

除了 DBCP2 的配置项,有一个配置项要特别注意,就是 spring-datasource.type。这个配置项用于指定连接池的类型,如果这里不进行指定,默认的是 HikariCP,则下面的配置项不会生效。测试程序与6.1.2节相同,这里不再重复。最终结果如下所示。

org.apache.commons.dbcp2.BasicDataSource@1fbf088b
org.apache.commons.dbcp2.BasicDataSource
jdbc:mysql://localhost:3308/test

所以,这里是 DBCP2 为数据源。对于 DBCP2 的配置项,这里只稍作解释,如果读者想了解更多可以查资料。

  • initial-size:连接初始值,连接池启动时创建的连接数量,默认为 0。

  • max-idle:最大空闲值,当经过一个高峰之后,连接池会释放不使用的连接,直到减少到 max-idle,默认为 8。

  • max-total:在同一个时刻被分配的连接池有效连接数的最大值,默认为 8。

  • Max-wait-millis:从连接池中获取一个连接,最大的等待时间,单位可以设置为毫秒。

  • Connect-properties:连接属性,格式为参数名=参数值。