30. 使用 SQL 数据库

Spring Framework为使用 SQL 数据库提供了广泛的支持,从使用JdbcTemplate的直接 JDBC 访问到完整的“对象关系 Map”技术(例如 Hibernate)。 Spring Data提供了更高级别的功能:直接从接口创建Repository实现,并使用约定从您的方法名称生成查询。

30.1 配置数据源

Java 的javax.sql.DataSource接口提供了使用数据库连接的标准方法。传统上,“数据源”使用URL以及一些凭据来构建数据库连接。

Tip

有关更高级的示例,请参见“操作方法”部分,通常可以完全控制 DataSource 的配置。

30.1.1 嵌入式数据库支持

通过使用内存嵌入式数据库来开发应用程序通常很方便。显然,内存数据库不提供持久存储。您需要在应用程序启动时填充数据库,并准备在应用程序结束时丢弃数据。

Tip

“操作方法”部分包括关于如何初始化数据库的部分

Spring Boot 可以自动配置嵌入式H2HSQLDerby数据库。您无需提供任何连接 URL。您只需要包含要使用的嵌入式数据库的构建依赖项即可。

Note

如果在测试中使用此功能,则可能会注意到,整个测试套件将重用同一数据库,而不管您使用的应用程序上下文的数量如何。如果要确保每个上下文都有一个单独的嵌入式数据库,则应将spring.datasource.generate-unique-name设置为true

例如,典型的 POM 依赖关系如下:

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
	<groupId>org.hsqldb</groupId>
	<artifactId>hsqldb</artifactId>
	<scope>runtime</scope>
</dependency>

Note

您需要依赖spring-jdbc才能自动配置嵌入式数据库。在此示例中,它通过spring-boot-starter-data-jpa暂时拉入。

Tip

如果出于某种原因确实为嵌入式数据库配置了连接 URL,请确保确保禁用了数据库的自动关闭功能。如果使用 H2,则应使用DB_CLOSE_ON_EXIT=FALSE。如果使用 HSQLDB,则应确保不使用shutdown=true。通过禁用数据库的自动关闭功能,Spring Boot 可以控制何时关闭数据库,从而确保一旦不再需要访问数据库时就可以执行该操作。

30.1.2 连接到生产数据库

生产数据库连接也可以使用池DataSource进行自动配置。 Spring Boot 使用以下算法来选择特定的实现:

如果使用spring-boot-starter-jdbcspring-boot-starter-data-jpa“启动器”,则会自动获得HikariCP的依赖项。

Note

您可以完全绕过该算法,并通过设置spring.datasource.type属性来指定要使用的连接池。如果您在 Tomcat 容器中运行应用程序,这一点尤其重要,因为默认情况下提供tomcat-jdbc

Tip

其他连接池始终可以手动配置。如果定义自己的DataSource bean,则不会进行自动配置。

数据源配置由spring.datasource.*中的外部配置属性控制。例如,您可以在application.properties中声明以下部分:

spring.datasource.url=jdbc:mysql://localhost/test
spring.datasource.username=dbuser
spring.datasource.password=dbpass
spring.datasource.driver-class-name=com.mysql.jdbc.Driver

Note

您至少应通过设置spring.datasource.url属性来指定 URL。否则,Spring Boot 会尝试自动配置嵌入式数据库。

Tip

您通常不需要指定driver-class-name,因为 Spring Boot 可以从url推导大多数数据库。

Note

对于要创建的池DataSource,我们需要能够验证一个有效的Driver类是否可用,因此我们在进行任何操作之前都要进行检查。换句话说,如果设置spring.datasource.driver-class-name=com.mysql.jdbc.Driver,则该类必须是可加载的。

有关更多受支持的选项,请参见DataSourceProperties。这些是与实际实现无关的标准选项。也可以使用它们各自的前缀(spring.datasource.hikari.*spring.datasource.tomcat.*spring.datasource.dbcp2.*)微调实现特定的设置。有关更多详细信息,请参考所用连接池实现的文档。

例如,如果您使用Tomcat 连接池,则可以自定义许多其他设置,如以下示例所示:

# Number of ms to wait before throwing an exception if no connection is available.
spring.datasource.tomcat.max-wait=10000

# Maximum number of active connections that can be allocated from this pool at the same time.
spring.datasource.tomcat.max-active=50

# Validate the connection before borrowing it from the pool.
spring.datasource.tomcat.test-on-borrow=true

30.1.3 连接到 JNDI 数据源

如果您将 Spring Boot 应用程序部署到 Application Server,则可能需要使用 Application Server 的内置功能来配置和 Management DataSource,并使用 JNDI 对其进行访问。

spring.datasource.jndi-name属性可以替代spring.datasource.urlspring.datasource.usernamespring.datasource.password属性,以从特定的 JNDI 位置访问DataSource。例如,application.properties中的以下部分显示了如何访问 JBoss AS 定义的DataSource

spring.datasource.jndi-name=java:jboss/datasources/customers

30.2 使用 JdbcTemplate

Spring 的JdbcTemplateNamedParameterJdbcTemplate类是自动配置的,您可以@Autowire直接将它们@Autowire放入自己的 bean 中,如以下示例所示:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;

@Component
public class MyBean {

	private final JdbcTemplate jdbcTemplate;

	@Autowired
	public MyBean(JdbcTemplate jdbcTemplate) {
		this.jdbcTemplate = jdbcTemplate;
	}

	// ...

}

您可以使用spring.jdbc.template.*属性来自定义模板的某些属性,如以下示例所示:

spring.jdbc.template.max-rows=500

Note

NamedParameterJdbcTemplate在后台重复使用相同的JdbcTemplate实例。如果定义了多个JdbcTemplate并且不存在主要候选对象,则不会自动配置NamedParameterJdbcTemplate

30.3 JPA 和 Spring Data JPA

Java Persistence API 是一种标准技术,可让您将对象“Map”到关系数据库。 spring-boot-starter-data-jpa POM 提供了一种快速的 Starter 方法。它提供以下关键依赖性:

Tip

在这里,我们不会过多讨论 JPA 或Spring Data的细节。您可以按照spring.io中的“使用 JPA 访问数据”指南进行操作,并阅读Spring Data JPAHibernate参考文档。

30.3.1 实体类

传统上,JPA“实体”类是在persistence.xml文件中指定的。对于 Spring Boot,此文件不是必需的,而是使用“实体扫描”。默认情况下,将搜索主配置类(用@EnableAutoConfiguration@SpringBootApplicationComments 的软件包)下的所有软件包。

任何带有@Entity@Embeddable@MappedSuperclassComments 的类。典型的实体类类似于以下示例:

package com.example.myapp.domain;

import java.io.Serializable;
import javax.persistence.*;

@Entity
public class City implements Serializable {

	@Id
	@GeneratedValue
	private Long id;

	@Column(nullable = false)
	private String name;

	@Column(nullable = false)
	private String state;

	// ... additional members, often include @OneToMany mappings

	protected City() {
		// no-args constructor required by JPA spec
		// this one is protected since it shouldn't be used directly
	}

	public City(String name, String state) {
		this.name = name;
		this.state = state;
	}

	public String getName() {
		return this.name;
	}

	public String getState() {
		return this.state;
	}

	// ... etc

}

Tip

您可以使用@EntityScanComments 来自定义实体扫描位置。请参阅“ 第 84.4 节“将@Entity 定义与 Spring 配置分开””方法。

30.3.2 Spring Data JPA 存储库

Spring Data JPA存储库是您可以定义以访问数据的接口。 JPA 查询是根据您的方法名称自动创建的。例如,一个CityRepository接口可能声明findAllByState(String state)方法来查找给定 State 的所有城市。

对于更复杂的查询,您可以使用 Spring Data 的QueryComments 对方法进行 Comments。

Spring Data 存储库通常从RepositoryCrudRepository接口扩展。如果使用自动配置,则会从包含主配置类(用@EnableAutoConfiguration@SpringBootApplicationComments 的主配置类)的包中搜索存储库。

以下示例显示了典型的 Spring Data 存储库接口定义:

package com.example.myapp.domain;

import org.springframework.data.domain.*;
import org.springframework.data.repository.*;

public interface CityRepository extends Repository<City, Long> {

	Page<City> findAll(Pageable pageable);

	City findByNameAndStateAllIgnoringCase(String name, String state);

}

Spring Data JPA 存储库支持三种不同的引导模式:默认,延迟和延迟。要启用延迟引导或延迟引导,请将spring.data.jpa.repositories.bootstrap-mode分别设置为deferredlazy。当使用延迟或延迟启动时,自动配置的EntityManagerFactoryBuilder将使用上下文的异步任务 Actuator(如果有)作为引导 Actuator。

Tip

我们几乎没有刮过 Spring Data JPA 的表面。有关完整的详细信息,请参见Spring Data JPA 参考文档

30.3.3 创建和删除 JPA 数据库

默认情况下,如果您使用嵌入式数据库(H2,HSQL 或 Derby),则仅“ **”自动创建 JPA 数据库。您可以使用spring.jpa.*属性来显式配置 JPA 设置。例如,要创建和删除表,可以将以下行添加到application.properties

spring.jpa.hibernate.ddl-auto=create-drop

Note

Hibernate 自己的内部属性名称是hibernate.hbm2ddl.auto(如果您记得更好的话)。您可以使用spring.jpa.properties.*来设置它以及其他 Hibernate 本机属性(将前缀添加到实体 Management 器之前,前缀会被删除)。下面的行显示了为 Hibernate 设置 JPA 属性的示例:

spring.jpa.properties.hibernate.globally_quoted_identifiers=true

前面示例中的行将hibernate.globally_quoted_identifiers属性的值true传递给 Hibernate 实体 Management 器。

默认情况下,DDL 执行(或验证)被推迟到ApplicationContext开始。还有一个spring.jpa.generate-ddl标志,但是如果 Hibernate 自动配置处于 Active 状态,则不使用它,因为ddl-auto设置更细粒度。

30.3.4 在视图中打开 EntityManager

如果您正在运行 Web 应用程序,则默认情况下,Spring Boot 注册OpenEntityManagerInViewInterceptor以应用“在视图中打开 EntityManager”模式,以允许在 Web 视图中进行延迟加载。如果您不希望出现这种情况,则应在application.properties中将spring.jpa.open-in-view设置为false

30.4 Spring Data JDBC

Spring Data 包括对 JDBC 的存储库支持,并将自动为CrudRepository上的方法生成 SQL。对于更高级的查询,提供了@QueryComments。

当必要的依赖项位于 Classpath 上时,Spring Boot 将自动配置 Spring Data 的 JDBC 存储库。只需依赖spring-boot-starter-data-jdbc即可将它们添加到您的项目中。如有必要,您可以通过向应用程序中添加@EnableJdbcRepositories注解或JdbcConfiguration子类来控制 Spring Data JDBC 的配置。

Tip

有关 Spring Data JDBC 的完整详细信息,请参阅reference documentation

30.5 使用 H2 的 Web 控制台

H2 database提供了browser-based console,Spring Boot 可以为您自动配置browser-based console。满足以下条件时,将自动配置控制台:

Tip

如果您不使用 Spring Boot 的开发人员工具,但仍想使用 H2 的控制台,则可以将spring.h2.console.enabled属性配置为true

Note

H2 控制台仅在开发期间使用,因此您应确保在 Producing 不要将spring.h2.console.enabled设置为true

30.5.1 更改 H2 控制台的路径

默认情况下,控制台位于/h2-console。您可以使用spring.h2.console.path属性来自定义控制台的路径。

30.6 使用 jOOQ

面向 Java 对象的查询(jOOQ)是Data Geekery的流行产品,它可以从数据库中生成 Java 代码,并允许您通过其流畅的 API 构建类型安全的 SQL 查询。商业版和开源版都可以与 Spring Boot 一起使用。

30.6.1 代码生成

为了使用 jOOQ 类型安全查询,您需要从数据库架构中生成 Java 类。您可以按照jOOQ 用户手册中的说明进行操作。如果您使用jooq-codegen-maven插件,并且还使用spring-boot-starter-parent“父 POM”,则可以安全地忽略该插件的<version>标签。您还可以使用 Spring Boot 定义的版本变量(例如h2.version)来声明插件的数据库依赖关系。以下 Lists 显示了一个示例:

<plugin>
	<groupId>org.jooq</groupId>
	<artifactId>jooq-codegen-maven</artifactId>
	<executions>
		...
	</executions>
	<dependencies>
		<dependency>
			<groupId>com.h2database</groupId>
			<artifactId>h2</artifactId>
			<version>${h2.version}</version>
		</dependency>
	</dependencies>
	<configuration>
		<jdbc>
			<driver>org.h2.Driver</driver>
			<url>jdbc:h2:~/yourdatabase</url>
		</jdbc>
		<generator>
			...
		</generator>
	</configuration>
</plugin>

30.6.2 使用 DSLContext

jOOQ 提供的流畅的 API 是通过org.jooq.DSLContext接口启动的。 Spring Boot 将DSLContext自动配置为 Spring Bean,并将其连接到应用程序DataSource。要使用DSLContext,您可以@Autowire,如以下示例所示:

@Component
public class JooqExample implements CommandLineRunner {

	private final DSLContext create;

	@Autowired
	public JooqExample(DSLContext dslContext) {
		this.create = dslContext;
	}

}

Tip

jOOQ 手册倾向于使用名为create的变量来保存DSLContext

然后,您可以使用DSLContext构造查询,如以下示例所示:

public List<GregorianCalendar> authorsBornAfter1980() {
	return this.create.selectFrom(AUTHOR)
		.where(AUTHOR.DATE_OF_BIRTH.greaterThan(new GregorianCalendar(1980, 0, 1)))
		.fetch(AUTHOR.DATE_OF_BIRTH);
}

30.6.3 jOOQ SQL 方言

除非已配置spring.jooq.sql-dialect属性,否则 Spring Boot 会确定要用于数据源的 SQL 方言。如果 Spring Boot 无法检测到方言,则使用DEFAULT

Note

Spring Boot 只能自动配置开源版本的 jOOQ 支持的方言。

30.6.4 自定义 jOOQ

通过定义自己的@Bean定义(可以在创建 jOOQ Configuration时使用)可以实现更高级的自定义。您可以为以下 jOOQ 类型定义 bean:

如果要完全控制 jOOQ 配置,也可以创建自己的org.jooq.Configuration @Bean

上一章 首页 下一章