29. 使用 SQL 数据库
Spring 框架为使用 SQL 数据库提供了广泛的支持。从使用JdbcTemplate
的直接 JDBC 访问到完整的“对象关系 Map”技术(例如 Hibernate)。 Spring Data 提供了更高级别的功能,可以直接从接口创建Repository
实现,并使用约定从您的方法名称生成查询。
29.1 配置数据源
Java 的javax.sql.DataSource
接口提供了使用数据库连接的标准方法。传统上,数据源使用URL
以及一些凭据来构建数据库连接。
Tip
还要查看“操作方法”部分以获取更多高级示例,通常可以完全控制 DataSource 的配置。
29.1.1 嵌入式数据库支持
使用内存嵌入式数据库开发应用程序通常很方便。显然,内存数据库不提供持久存储。您需要在应用程序启动时填充数据库,并准备在应用程序结束时丢弃数据。
Tip
“操作方法”部分包含* 关于如何初始化数据库的部分 *
Spring Boot 可以自动配置嵌入式H2,HSQL和Derby数据库。您无需提供任何连接 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 可以控制何时关闭数据库,从而确保一旦不再需要对数据库的访问,它就会发生。
29.1.2 连接到生产数据库
生产数据库连接也可以使用池DataSource
进行自动配置。这是用于选择特定实现的算法:
-
我们更喜欢 Tomcat 池
DataSource
的性能和并发性,因此,如果可用,我们总是选择它。 -
否则,如果有 HikariCP,我们将使用它。
-
如果 Tomcat 池数据源和 HikariCP 都不可用,并且 Commons DBCP 可用,我们将使用它,但是我们不建议在 Producing 使用它,并且不建议使用它。
-
最后,如果 Commons DBCP2 可用,我们将使用它。
如果您使用spring-boot-starter-jdbc
或spring-boot-starter-data-jpa
'starters',您将自动获得对tomcat-jdbc
的依赖。
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.tomcat.*
,spring.datasource.hikari.*
和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
29.1.3 连接到 JNDI 数据源
如果要将 Spring Boot 应用程序部署到 Application Server,则可能需要使用 Application Server 的内置功能配置和 ManagementDataSource,并使用 JNDI 访问它。
spring.datasource.jndi-name
属性可以替代spring.datasource.url
,spring.datasource.username
和spring.datasource.password
属性,以从特定的 JNDI 位置访问DataSource
。例如,application.properties
中的以下部分显示了如何访问 JBoss AS 定义的DataSource
:
spring.datasource.jndi-name=java:jboss/datasources/customers
29.2 使用 JdbcTemplate
Spring 的JdbcTemplate
和NamedParameterJdbcTemplate
类是自动配置的,您可以@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;
}
// ...
}
29.3 JPA 和“Spring Data”
Java Persistence API 是一种标准技术,允许您将对象“Map”到关系数据库。 spring-boot-starter-data-jpa
POM 提供了一种快速的 Starter 方法。它提供以下关键依赖性:
-
Hibernate —最受欢迎的 JPA 实现之一。
-
Spring Data JPA-使实施基于 JPA 的存储库变得容易。
-
Spring ORM – Spring Framework 的核心 ORM 支持。
Tip
在这里,我们将不涉及 JPA 或 Spring Data 的太多细节。您可以遵循spring.io的“使用 JPA 访问数据”指南并阅读Spring Data JPA和Hibernate参考文档。
Note
默认情况下,Spring Boot 使用 Hibernate5.0.x。但是,如果您愿意,也可以使用 4.3.x 或 5.2.x。请参考Hibernate 4和Hibernate 5.2示例以了解操作方法。
29.3.1 实体类
传统上,JPA“实体”类是在persistence.xml
文件中指定的。在 Spring Boot 中,此文件不是必需的,而是使用“实体扫描”。默认情况下,将搜索主配置类(用@EnableAutoConfiguration
或@SpringBootApplication
Comments 的一个)下的所有软件包。
任何带有@Entity
,@Embeddable
或@MappedSuperclass
Comments 的类。典型的实体类如下所示:
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.country = country;
}
public String getName() {
return this.name;
}
public String getState() {
return this.state;
}
// ... etc
}
Tip
您可以使用@EntityScan
Comments 来自定义实体扫描位置。请参阅* 第 77.4 节“从 Spring 配置中分离@Entity 定义” *操作方法。
29.3.2 Spring Data JPA 存储库
Spring Data JPA 存储库是可以定义以访问数据的接口。 JPA 查询是根据您的方法名称自动创建的。例如,一个CityRepository
接口可以声明findAllByState(String state)
方法来查找给定 State 的所有城市。
对于更复杂的查询,您可以使用 Spring Data 的QueryComments 对方法进行 Comments。
Spring Data 存储库通常从Repository或CrudRepository接口扩展。如果使用的是自动配置,则会从包含主配置类(用@EnableAutoConfiguration
或@SpringBootApplication
Comments 的主配置类)的程序包中搜索存储库。
这是典型的 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 findByNameAndCountryAllIgnoringCase(String name, String country);
}
Tip
我们几乎没有刮过 Spring Data JPA 的表面。有关完整的详细信息,请检查其reference documentation。
29.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 器之前,前缀会被删除)。例:
spring.jpa.properties.hibernate.globally_quoted_identifiers=true
将hibernate.globally_quoted_identifiers
传递给 Hibernate 实体 Management 器。
默认情况下,DDL 执行(或验证)推迟到ApplicationContext
启动之前。还有一个spring.jpa.generate-ddl
标志,但是如果 Hibernate autoconfig 处于 Active 状态,则不使用它,因为ddl-auto
设置更细粒度。
29.3.4 在视图中打开 EntityManager
如果您正在运行 Web 应用程序,则默认情况下,Spring Boot 将注册OpenEntityManagerInViewInterceptor以应用“在视图中打开 EntityManager”模式,即允许在 Web 视图中进行延迟加载。如果您不希望出现这种情况,则应在application.properties
中将spring.jpa.open-in-view
设置为false
。
29.4 使用 H2 的 Web Console
H2 database提供了browser-based console,Spring Boot 可以为您自动配置browser-based console。满足以下条件时,将自动配置控制台:
-
您正在开发 Web 应用程序
-
com.h2database:h2
在Classpath上 -
您正在使用Spring Boot 的开发人员工具
Tip
如果您不使用 Spring Boot 的开发人员工具,但仍想使用 H2 的控制台,则可以通过将spring.h2.console.enabled
属性配置为true
来实现。 H2 控制台仅在开发期间使用,因此应注意确保在 Producing 未将spring.h2.console.enabled
设置为true
。
29.4.1 更改 H2 控制台的路径
默认情况下,该控制台位于/h2-console
。您可以使用spring.h2.console.path
属性来自定义控制台的路径。
29.4.2 保护 H2 控制台
当 Spring Security 在 Classpath 上并启用基本身份验证时,将使用基本身份验证自动保护 H2 控制台。可以使用以下属性来自定义安全性配置:
-
security.user.role
-
security.basic.authorize-mode
-
security.basic.enabled
29.5 使用 jOOQ
面向 Java 对象的查询(jOOQ)是Data Geekery的流行产品,它从数据库中生成 Java 代码,并允许您通过其流畅的 API 来构建类型安全的 SQL 查询。商业版和开源版都可以与 Spring Boot 一起使用。
29.5.1 代码生成
为了使用 jOOQ 类型安全查询,您需要从数据库架构中生成 Java 类。您可以按照jOOQ 用户手册中的说明进行操作。如果您使用的是jooq-codegen-maven
插件(并且还使用spring-boot-starter-parent
“父 POM”),则可以安全地省略该插件的<version>
标签。您还可以使用 Spring Boot 定义的版本变量(例如h2.version
)声明插件的数据库依赖关系。这是一个例子:
<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>
29.5.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);
}
29.5.3 自定义 jOOQ
您可以通过在application.properties
中设置spring.jooq.sql-dialect
来自定义 jOOQ 使用的 SQL 方言。例如,要指定 Postgres,您可以添加:
spring.jooq.sql-dialect=Postgres
通过定义自己的@Bean
定义(可以在创建 jOOQ Configuration
时使用)可以实现更高级的自定义。您可以为以下 jOOQ 类型定义 bean:
-
ConnectionProvider
-
TransactionProvider
-
RecordMapperProvider
-
RecordListenerProvider
-
ExecuteListenerProvider
-
VisitListenerProvider
如果要完全控制 jOOQ 配置,也可以创建自己的org.jooq.Configuration
@Bean
。