On this page
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
。