23. Data(五)-Spring Data JPA(配置,Bootstrap Mode,数据库初始化,命名策略)
23. Data(五)-Spring Data JPA(配置,Bootstrap Mode,数据库初始化,命名策略)
JPA 配置
Spring Data JPA 已经提供了一些独立于供应商的配置选项(例如 SQL 日志),Spring Boot 将这些选项以及一些针对Hibernate
的选项作为外部配置属性公开。其中一些是根据上下文自动检测的,因此你不应该设置它们。
属性 | 描述 | 备注 |
---|---|---|
spring.jpa.database | 要操作的目标数据库,默认自动检测 | 可选配置 |
spring.jpa.database-platform | 要操作的目标数据库的名称,默认情况下是自动检测的 | 可以使用"Database "枚举 |
spring.jpa.defer-datasource-initialization | datasource 初始化延迟 | 默认false |
spring.jpa.generate-ddl | 启动时是否初始化数据库schema | 默认false |
spring.jpa.show-sql | 是否启用SQL语句日志记录 | 默认false |
spring.jpa.mapping-resources | 资源映射(等价于persistence.xml 中的“mapping-file ”条目) | |
spring.jpa.open-in-view | OpenEntityManagerInViewInterceptor 注册,将JPA EntityManager 绑定到线程,用于整个请求处理 | 默认true |
spring.jpa.properties | 要在JPA提供程序上设置的其他本地属性 | 例如:spring.jpa.properties.hibernate.connection.autocommit |
spring.data.jpa.repositories.enabled | 是否启用JPA Repository | 默认true |
spring.data.jpa.repositories.bootstrap-mode | JPA Repository 的引导模式 | 三种模式:DEFAULT (默认), DEFERRED ,LAZY |
spring.jpa.hibernate.ddl-auto | DDL模式 | hibernate.hbm2ddl 的快捷方式,当使用嵌入式数据库时,默认为create-drop ,否则默认值为 none |
spring.jpa.hibernate.naming.implicit-strategy | 全限定名的隐式命名策略 | 例如:org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy |
spring.jpa.hibernate.naming.physical-strategy | 物理命名策略的完全限定名 | |
spring.jpa.hibernate.use-new-id-generator-mappings | 是否使用Hibernate更新的IdentifierGenerator AUTO , TABLE 和SEQUENCE 。 | 默认true 。hibernate.id.new_generator_mappings 快捷方式 |
Bootstrap Mode
默认情况下,Spring Data JPA Repository 是默认的 Spring bean。它们是单例作用域,并且是提前初始化的。在启动期间,它们已经与 JPA EntityManager
交互,以进行验证和元数据分析。Spring 框架支持在后台线程中初始化JPA EntityManagerFactory
,因为在 Spring 应用程序中,这个过程通常会占用大量的启动时间。为了有效地利用后台初始化,我们需要确保 JPA Repository 的初始化时间越晚越好。
在 Spring Data JPA 中,可以使用spring.data.jpa.repositories.bootstrap-mode
配置BootstrapMode
:
- DEFAULT (默认) — 默认模式,除非显示的使用@Lazy 注解延迟加载,否则 Repository 在容器启动过程中初始化。
- LAZY — 懒加载模式,启动过程中 JPA Respository 组件 bean 并没有真正被初始化。这些 JPA Respository 组件 bean 仅在首次调用前才会被初始化,以及进行相应的验证和元数据分析。
- DEFERRED —延迟加载模式,本质上和 LAZY 操作模式相同,但是触发一个 ContextRefreshedEvent 事件来通知 Respository 初始化,这样 Respository 在应用程序完全启动之前就被验证了。
模式选择建议:
1.如果你不使用异步 JPA 引导,则坚持使用默认引导模式。
2.如果你想异步引导 JPA,DEFERRED
是一个合理的默认值,因为它将确保 Spring Data
JPA 引导只等待EntityManagerFactory
设置,如果EntityManagerFactory
设置本身需要比初始化所有其他应用程序组件更长的时间。尽管如此,它确保存储库在应用程序发出启动信号之前得到了正确的初始化和验证。
3.对于测试场景和本地开发,LAZY
是一个不错的选择。
命名策略
Hibernate 使用两种不同的命名策略将对象模型中的名称映射到相应的数据库名称。物理策略
和隐式策略
实现的完全限定类名,可以通过分别设置spring.jpa.hibernate.naming.physical-strategy
和spring.jpa.hibernate.naming.implicit-strategy
属性来配置。如果ImplicitNamingStrategy
或PhysicalNamingStrategy
bean 在应用程序上下文中可用,Hibernate 将自动配置使用它们。
默认情况下,Spring Boot 使用CamelCaseToUnderscoresNamingStrategy
配置物理命名策略。使用这种策略,所有的点都被下划线取代
,驼峰大小写也被下划线取代
。另外,默认情况下,所有表名都是小写的。例如,TelephoneNumber
实体被映射到telephone_number
表。如果你的模式需要混合大小写标识符,定义一个自定义CamelCaseToUnderscoresNamingStrategy
bean,如下面的示例所示:
@Configuration(proxyBeanMethods = false)
public class MyHibernateConfiguration {
@Bean
public CamelCaseToUnderscoresNamingStrategy caseSensitivePhysicalNamingStrategy() {
return new CamelCaseToUnderscoresNamingStrategy() {
@Override
protected boolean isCaseInsensitive(JdbcEnvironment jdbcEnvironment) {
return false;
}
};
}
}
数据库初始化
一个SQL
数据库可以用不同的方式初始化,这取决于你的技术栈是什么。
使用 JPA 初始化数据库
JPA 具有用于 DDL 生成的特性,可以将这些特性设置为在启动时针对数据库运行。这是通过两个外部属性控制的:
spring.jpa.generate-ddl (boolean)
: 开启和关闭该特性,并且与厂商无关。spring.jpa.hibernate.ddl-auto (enum)
:是以更细粒度的方式控制行为的 Hibernate 特性。
ddl-auto
枚举:none
(默认):禁用DDL
处理validate
:验证 schema,不对数据库做任何操作update
: 更新 schemacreate
: 创建 schema,并销毁之前数据create-drop
: 会话创建时创建 schema,会话关闭时销毁 schema
使用 Hibernate 初始化数据库
你可以显式地设置spring.jpa.hibernate.ddl-auto
,标准的 Hibernate 属性值为none
、validate
、update
、create
和create-drop
。 根据 Spring Boot 是否认为数据库是嵌入式的,它会为你选择一个默认值。如果没有检测到 schema 管理器,或者在所有其他情况下都没有检测到schema
管理器,则默认为create-drop
。通过查看 Connection 类型和 JDBC url 来检测嵌入式数据库(Hsqldb
、h2
和Derby
是候选项)。从内存数据库切换到“真正的”数据库时要小心,不要假设新平台中存在表和数据。你要么必须显式地设置ddl-auto
,要么使用其他机制之一来初始化数据库。
你可以通过启用
org.hibernate.SQL
日志记录器来输出模式创建。如果你启用调试模式,这将自动完成。
另外,在classpath
根目录命名为import.sql
的文件,Hibernate 在启动时执行此文件(如果将ddl-auto
属性设置为create
或create-drop
)。这个是 Hibernate 的特性。
新建实体类:
@Entity
public class Blog {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String title;
private String content;
//get set
}
配置:
spring:
datasource:
#数据库驱动完整类名
driver-class-name: com.mysql.jdbc.Driver
#数据库连接url
url: jdbc:mysql://127.0.0.1:3306/spring-boot-data-learn
#数据库用户名
username: root
#数据库密码
password: 123456
jpa:
hibernate:
ddl-auto: create
logging:
level:
org.hibernate.SQL: debug
启动程序:
HHH000400: Using dialect: org.hibernate.dialect.MySQL57Dialect
org.hibernate.SQL : drop table if exists blog
org.hibernate.SQL : create table blog (id bigint not null auto_increment, content varchar(255), title varchar(255), primary key (id)) engine=InnoDB
使用 SQL 脚本初始化
Spring Boot 可以自动创建 JDBC DataSource Schema
(DDL
脚本)或R2DBC ConnectionFactory
并初始化它(DML
脚本)。 它从标准classpath
的根路径位置:分别加载schema.sql
和 data.sql
。
另外,Spring Boot 还自动处理schema-${platform}.sql
和 data-${platform}.sql
(如果存在)文件,platform
的值来自spring.sql.init.platform
变量。这允许你在必要时切换到特定于数据库的脚本。例如,你可以选择将其设置为数据库(hsqldb
、h2
、oracle
、mysql
、postgresql
等)的供应商名称。
默认情况下,只有在使用嵌入式内存数据库时才执行SQL
数据库初始化。 要始终初始化一个SQL
数据库,不管它是什么类型,请将spring.sql.init.mode
设置为always
。类似地,要禁用初始化,可以将spring.sql.init.mode
设置为never
。默认情况下,Spring Boot 启用其基于脚本的数据库初始化器的快速失败特性。这意味着,如果脚本导致异常,应用程序将无法启动。你可以通过设置spring.sql.init.continue-on-error
来调整该行为。
默认情况下,在创建 JPA EntityManagerFactory bean 之前执行基于脚本的数据源初始化。schema.sql
可用于为 JPA-managed 的实体创建schema
,data.sql
可以填充它。
不建议使用多个数据源初始化技术,如果你希望基于脚本的数据源初始化能够构建在 Hibernate 执行的 schema 创建之上,请将spring.jpa.defer-datasource-initialization
设置为true
。这将推迟数据源初始化,直到创建并初始化任何 EntityManagerFactory bean 之后。
如果你正在使用高级数据库迁移工具,如Flyway
或Liquibase
,你应该单独使用它们来创建和初始化schema
。不建议在Flyway
或Liquibase
一起使用schema.sql
和 data.sql
,并且在未来的版本中将删除支持。
新建 resources/schema.sql 和 data.sql
//schema.sql
create table blog_always (id bigint not null auto_increment, content varchar(255), title varchar(255), primary key (id)) engine=InnoDB;
//data.sql
INSERT INTO blog_always(title,content)
VALUES('hello word',"content");
application.yaml 配置
spring:
datasource:
#数据库驱动完整类名
driver-class-name: com.mysql.jdbc.Driver
#数据库连接url
url: jdbc:mysql://127.0.0.1:3306/spring-boot-data-learn
#数据库用户名
username: root
#数据库密码
password: 123456
jpa:
hibernate:
ddl-auto: create
sql:
init:
mode: always
continue-on-error: false
logging:
level:
org.hibernate.SQL: debug
启动程序:
使用 Spring Batch 初始化数据库
如果你使用 Spring Batch,那么它已经预先打包了用于大多数流行数据库平台的SQL
初始化脚本。 Spring Boot 可以检测你的数据库类型,并在启动时执行这些脚本。如果使用嵌入式数据库,默认情况下会发生这种情况。你也可以为任何数据库类型启用它,如下所示的示例:
spring:
batch:
jdbc:
initialize-schema: "always"
你还可以通过设置spring.batch.jdbc.initialize-schema=never
显式地关闭初始化。
数据库初始化依赖
数据库初始化是在应用程序启动时作为应用程序上下文刷新的一部分执行的。为了允许在启动期间访问已初始化的数据库,将自动检测充当数据库初始化器的 bean 和要求对数据库进行初始化的 bean。其初始化依赖于已初始化的数据库的 bean 被配置为依赖于那些初始化数据库的 bean。如果在启动期间,应用程序试图访问数据库,而数据库还没有初始化,则可以配置对初始化数据库并要求初始化数据库的 bean 的额外检测
检测数据库初始化器
Spring Boot 将自动检测以下类型的 bean 来初始化 SQL 数据库:
- DataSourceScriptDatabaseInitializer
- EntityManagerFactory
- Flyway
- FlywayMigrationInitializer
- R2dbcScriptDatabaseInitializer
- SpringLiquibase
如果你正在为数据库初始化库使用第三方启动器,那么它可能会提供一个检测器,以便自动检测其他类型的bean
。要检测其他bean
,请在META-INF/spring-factories
中注册一个DatabaseInitializerDetector
实现。
检测依赖于数据库初始化的 Bean
Spring Boot 将自动检测以下类型的依赖于数据库初始化的bean
:
- AbstractEntityManagerFactoryBean (除非 spring.jpa.defer-datasource-initialization 设置为 true)
- DSLContext (jOOQ)
- EntityManagerFactory (除非 spring.jpa.defer-datasource-initialization 设置为 true)
- JdbcOperations
- NamedParameterJdbcOperations
如果你正在使用第三方starter
数据访问库,它可能会提供一个检测器,以便自动检测其他类型的 bean。要检测其他 bean,请在META-INF/spring-factories
中注册一个DependsOnDatabaseInitializationDetector
实现。或者,用@DependsOnDatabaseInitialization
注解的 bean 的类或它的@Bean
方法。