Spring框架为使用SQL数据库提供了广泛支持,从使用JdbcTemplate
直接访问JDBC到完全的‘对象关系映射’技术,比如Hibernate。Spring Data提供了更高级的功能,直接从接口创建Repository
实现,并根据约定从方法名生成查询。
Java的javax.sql.DataSource
接口提供了一个标准的使用数据库连接的方法。通常,DataSource使用URL
和相应的凭证去初始化数据库连接。
开发应用时使用内存数据库是很方便的。显然,内存数据库不提供持久化存储;你只需要在应用启动时填充数据库,在应用结束前预先清除数据。
Spring Boot可以自动配置的内嵌数据库包括H2, HSQL和Derby。你不需要提供任何连接URLs,只需要添加你想使用的内嵌数据库依赖。
示例:典型的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控制何时关闭数据库,因此在数据库不需要时可以确保关闭只发生一次。
生产环境的数据库连接可以通过池化的DataSource
进行自动配置,下面是选取特定实现的算法:
如果使用spring-boot-starter-jdbc
或spring-boot-starter-data-jpa
'starters',你会自动添加tomcat-jdbc
依赖。
注 通过指定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
,然后该class加载出来,否则就会出错。
其他可选配置可以查看DataSourceProperties,有些标准配置是跟实现无关的,对于实现相关的配置可以通过相应前缀进行设置(spring.datasource.tomcat.*
,spring.datasource.hikari.*
,spring.datasource.dbcp.*
和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
如果正在将Spring Boot应用部署到一个应用服务器,你可能想要用应用服务器内建的特性来配置和管理你的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
Spring的JdbcTemplate
和NamedParameterJdbcTemplate
类会被自动配置,你可以将它们直接@Autowire
到自己的beans:
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;
}
// ...
}
Java持久化API是一个允许你将对象映射为关系数据库的标准技术,spring-boot-starter-data-jpa
POM提供了一种快速上手的方式,它提供以下关键依赖:
注 我们不想在这涉及太多关于JPA或Spring Data的细节。你可以参考来自spring.io的指南使用JPA获取数据,并阅读Spring Data JPA和Hibernate的参考文档。
注 Spring Boot默认使用Hibernate 5.0.x,如果你希望的话也可以使用4.3.x或5.2.x,具体参考Hibernate 4和Hibernate 5.2示例。
通常,JPA实体类被定义到一个persistence.xml
文件,在Spring Boot中,这个文件被'实体扫描'取代。默认情况,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.country = country;
}
public String getName() {
return this.name;
}
public String getState() {
return this.state;
}
// ... etc
}
注 你可以使用@EntityScan
注解自定义实体扫描路径,具体参考Section 74.4, “Separate @Entity definitions from Spring configuration”。
Spring Data JPA仓库(repositories)是用来定义访问数据的接口。根据你的方法名,JPA查询会被自动创建,比如,一个CityRepository
接口可能声明一个findAllByState(String state)
方法,用来查找给定状态的所有城市。
对于比较复杂的查询,你可以使用Spring Data的Query
注解你的方法。
Spring Data仓库通常继承自Repository
或CrudRepository
接口。如果你使用自动配置,Spring Boot会搜索主配置类(注解@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 findByNameAndCountryAllIgnoringCase(String name, String country);
}
注:我们仅仅触及了Spring Data 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其他的native属性,比如:spring.jpa.properties.hibernate.globally_quoted_identifiers=true
将传递hibernate.globally_quoted_identifiers
到Hibernate实体管理器。
通常,DDL执行(或验证)被延迟到ApplicationContext
启动后,这可以通过spring.jpa.generate-ddl
标签控制,如果Hibernate自动配置被激活,那该标识就不会被使用,因为ddl-auto
设置粒度更细。
H2数据库提供一个基于浏览器的控制台,Spring Boot可以为你自动配置。如果以下条件满足,则控制台会被自动配置:
com.h2database:h2
依赖。注 如果你没有使用Spring Boot的开发者工具,仍想利用H2的控制台,可以设置spring.h2.console.enabled
属性值为true
。H2控制台应该只用于开发期间,所以确保生产环境没有设置spring.h2.console.enabled
。
H2控制台路径默认为/h2-console
,你可以通过设置spring.h2.console.path
属性自定义该路径。
当添加Spring Security依赖,并且启用基本认证时,Spring Boot自动使用基本认证保护H2控制台。以下属性可用于自定义安全配置:
security.user.role
security.basic.authorize-mode
security.basic.enabled
Java面向对象查询(jOOQ)是Data Geekery的一个明星产品,可以从数据库生成Java代码,让你通过它的流式API构建类型安全的SQL查询。不管是商业版,还是开源版本都能跟Spring Boot一块使用。
为了使用jOOQ类型安全的查询,你需要从数据库schema生成Java类,具体可参考jOOQ用户指南。如果正在使用jooq-codegen-maven
插件(也使用spring-boot-starter-parent
“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>
jOOQ提供的流式(fluent)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);
}
通过在application.properties
中设置spring.jooq.sql-dialect
属性,你可以自定义jOOQ使用的SQL方言(dialect)。例如,设置方言为Postgres:
spring.jooq.sql-dialect=Postgres
定义自己的@Bean
,在jOOQConfiguration
创建时使用,可以实现更高级的定制。你可以为以下jOOQ类型定义beans:
ConnectionProvider
TransactionProvider
RecordMapperProvider
RecordListenerProvider
ExecuteListenerProvider
VisitListenerProvider
如果想全面控制jOOQ配置,你甚至可以创建自己的org.jooq.Configuration
@Bean
。