4.9 使用SQL数据库
Spring Framework为使用SQL数据库提供了广泛的支持,从使用JdbcTemplate的直接JDBC访问到完成“对象关系映射”技术(如Hibernate)。 Spring Data提供了更多级别的功能:直接从接口创建存储库实现,并使用约定从方法名称生成查询。
4.9.1 配置数据源
Java的javax.sql.DataSource接口提供了一种处理数据库连接的标准方法。 传统上,“DataSource”使用URL和一些凭据来建立数据库连接。
有关更多高级示例,请参阅“操作方法”部分,通常可以完全控制DataSource的配置。
4.9.1.1 嵌入式数据库支持
通过使用内存中的嵌入式数据库来开发应用程序通常很方便。 显然,内存数据库不提供持久存储。 您需要在应用程序启动时填充数据库,并准备在应用程序结束时丢弃数据。
“操作方法”部分包含有关如何初始化数据库的部分。
Spring Boot可以自动配置嵌入式H2,HSQL和Derby数据库。 您无需提供任何连接URL。 您只需要包含要使用的嵌入式数据库的构建依赖项。
如果您在测试中使用此功能,您可能会注意到整个测试套件都会重复使用相同的数据库,而不管您使用的应用程序上下文的数量。 如果要确保每个上下文都有一个单独的嵌入式数据库,则应将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>
您需要依赖spring-jdbc才能自动配置嵌入式数据库。 在这个例子中,它通过spring-boot-starter-data-jpa传递。
如果由于某种原因,您确实为嵌入式数据库配置了连接URL,请注意确保禁用数据库的自动关闭。 如果使用H2,则应使用DB_CLOSE_ON_EXIT = FALSE来执行此操作。 如果使用HSQLDB,则应确保不使用shutdown = true。 禁用数据库的自动关闭可以在数据库关闭时进行Spring Boot控制,从而确保在不再需要访问数据库时发生。
4.9.1.2 连接到生产数据库
还可以使用池化DataSource自动配置生产数据库连接。 Spring Boot使用以下算法来选择特定的实现:
- 我们更喜欢HikariCP的性能和并发性。 如果HikariCP可用,我们总是选择它。
- 否则,如果Tomcat池化DataSource可用,我们将使用它。
- 如果HikariCP和Tomcat池化数据源都不可用,并且Commons DBCP2可用,我们就会使用它。
如果使用spring-boot-starter-jdbc或spring-boot-starter-data-jpa“starters”,则会自动获得对HikariCP的依赖。
您可以完全绕过该算法,并通过设置spring.datasource.type属性指定要使用的连接池。 如果您在Tomcat容器中运行应用程序,这一点尤为重要,因为默认情况下会提供tomcat-jdbc。
始终可以手动配置其他连接池。 如果您定义自己的DataSource bean,则不会进行自动配置。
DataSource配置由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
您至少应该通过设置spring.datasource.url属性来指定URL。 否则,Spring Boot会尝试自动配置嵌入式数据库。
您通常不需要指定driver-class-name,因为Spring Boot可以从url中为大多数数据库推断出它。
对于要创建的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
4.9.1.3 连接到JNDI数据源
如果将Spring Boot应用程序部署到Application Server,则可能需要使用Application Server的内置功能配置和管理DataSource,并使用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
4.9.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;
}
// ...
}
您可以使用spring.jdbc.template.*属性自定义模板的某些属性,如以下示例所示:
spring.jdbc.template.max-rows=500
NamedParameterJdbcTemplate在后台重用相同的JdbcTemplate实例。 如果定义了多个JdbcTemplate且不存在主要候选项,则不会自动配置NamedParameterJdbcTemplate。
4.9.3 JPA 和 Spring Data JPA
Java Persistence API是一种标准技术,可让您将对象“映射”到关系数据库。 spring-boot-starter-data-jpa POM提供了一种快速入门方式。 它提供以下关键依赖项:
- Hibernate:最受欢迎的JPA实现之一。
- Spring Data JPA:使实现基于JPA的存储库变得容易。
- Spring ORMs:Spring Framework的核心ORM支持。
我们不会在这里详细介绍JPA或Spring Data。 您可以按照spring.io中的“使用JPA访问数据”指南阅读Spring Data JPA和Hibernate参考文档。
4.9.3.1 实体类
传统上,JPA“Entity”类在persistence.xml文件中指定。 使用Spring Boot,此文件不是必需的,而是使用“实体扫描”。 默认情况下,将搜索主配置类(使用@EnableAutoConfiguration或@SpringBootApplication注释的那个)下的所有包。
任何使用@Entity,@Embeddable或@MappedSuperclass注释的类都被考虑在内。 典型的实体类类似于以下示例:
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
}
您可以使用@EntityScan批注自定义实体扫描位置。 请参阅“9.9.4 从Spring配置中分离@Entity定义”。
4.9.3.2 Spring Data JPA Repositories
Spring Data JPA存储库是您可以定义以访问数据的接口。 JPA查询是从您的方法名称自动创建的。 例如,CityRepository接口可能会声明findAllByState(String state)方法以查找给定状态中的所有城市。
对于更复杂的查询,可以使用Spring Data Query批注对方法进行批注。
Spring Data存储库通常从Repository或CrudRepository接口扩展。 如果使用自动配置,则会从包含主配置类(使用@EnableAutoConfiguration或@SpringBootApplication注释的那个)的包中搜索存储库。
以下示例显示了典型的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存储库支持三种不同的引导模式:default,deferred和lazy。 要启用延迟或延迟引导,请将spring.data.jpa.repositories.bootstrap-mode分别设置为deferred或lazy。 使用延迟或延迟引导时,自动配置的EntityManagerFactoryBuilder将使用上下文的AsyncTaskExecutor(如果有)作为引导程序执行程序。 如果存在多个,则将使用名为applicationTaskExecutor的那个。
我们几乎没有涉及Spring Data JPA的皮毛。 有关完整的详细信息,请参阅Spring Data JPA参考文档。
4.9.3.3 创建和删除JPA数据库
默认情况下,仅当您使用嵌入式数据库(H2,HSQL或Derby)时,才会自动创建JPA数据库。 您可以使用spring.jpa.*属性显式配置JPA设置。 例如,要创建和删除表,可以将以下行添加到application.properties:
spring.jpa.hibernate.ddl-auto=create-drop
Hibernate自己的内部属性名称(如果你碰巧记得更好)是hibernate.hbm2ddl.auto。 您可以使用spring.jpa.properties.*(在将它们添加到实体管理器之前剥离前缀)来设置它以及其他Hibernate本机属性。 以下行显示了为Hibernate设置JPA属性的示例:
spring.jpa.properties.hibernate.globally_quoted_identifiers=true
前面示例中的行将hibernate.globally_quoted_identifiers属性的值传递给Hibernate实体管理器。
默认情况下,DDL执行(或验证)将延迟到ApplicationContext启动。 还有一个spring.jpa.generate-ddl标志,但如果Hibernate自动配置处于活动状态,则不会使用它,因为ddl-auto设置更精细。
4.9.3.4 在View中打开EntityManager
如果您正在运行Web应用程序,Spring Boot默认会注册OpenEntityManagerInViewInterceptor以应用“在视图中打开EntityManager”模式,以允许在Web视图中进行延迟加载。 如果您不想要此行为,则应在application.properties中将spring.jpa.open-in-view设置为false。
4.9.4 Spring Data JDBC
Spring Data包含对JDBC的存储库支持,并将自动为CrudRepository上的方法生成SQL。 对于更高级的查询,提供了@Query注释。
当必要的依赖项在类路径上时,Spring Boot将自动配置Spring Data的JDBC存储库。 它们可以通过spring-boot-starter-data-jdbc的单一依赖项添加到项目中。 如有必要,可以通过将@EnableJdbcRepositories批注或JdbcConfiguration子类添加到应用程序来控制Spring Data JDBC的配置。
有关Spring Data JDBC的完整详细信息,请参阅参考文档。 |
4.9.5 使用 H2’s Web控制台
H2数据库提供了一个基于浏览器的控制台,Spring Boot可以为您自动配置。 满足以下条件时,将自动配置控制台:
- 您正在开发基于servlet的Web应用程序。
- com.h2database:h2在类路径上。
- 您正在使用Spring Boot的开发人员工具。
如果您没有使用Spring Boot的开发人员工具但仍想使用H2的控制台,则可以使用值true配置spring.h2.console.enabled属性。
H2控制台仅用于开发期间,因此您应该注意确保spring.h2.console.enabled在生产中未设置为true。
4.9.5.1 更改H2控制台的路径
默认情况下,控制台位于/h2-console。 您可以使用spring.h2.console.path属性自定义控制台的路径。
4.9.6 使用jOOQ
Java面向对象查询(jOOQ)是Data Geekery的一个流行产品,它从您的数据库生成Java代码,并允许您通过其Stream的API构建类型安全的SQL查询。 商业版和开源版都可以与Spring Boot一起使用。
4.9.6.1 代码生成
为了使用jOOQ类型安全查询,您需要从数据库模式生成Java类。 您可以按照jOOQ用户手册中的说明进行操作。 如果您使用jooq-codegen-maven插件并且还使用spring-boot-starter-parent“父POM”,则可以安全地省略插件的标记。 您还可以使用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>
4.9.6.2 使用DSLContext
jOOQ提供的Stream 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;
}
}
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);
}
4.9.6.3 jOOQ数据库方言
除非已配置spring.jooq.sql-dialect属性,否则Spring Boot会确定要用于数据源的SQL方言。 如果Spring Boot无法检测到方言,则使用DEFAULT。
Spring Boot只能自动配置开源版本的jOOQ支持的方言.
4.9.6.4 自定义jOOQ
通过定义自己的@Bean定义可以实现更高级的自定义,这些定义在创建jOOQ配置时使用。 您可以为以下jOOQ类型定义bean:
- ConnectionProvider
- ExecutorProvider
- TransactionProvider
- RecordMapperProvider
- RecordUnmapperProvider
- RecordListenerProvider
- ExecuteListenerProvider
- VisitListenerProvider
- TransactionListenerProvider
如果要完全控制jOOQ配置,还可以创建自己的org.jooq.Configuration @Bean。