Hibernate ORM 中文操作指南
2. Configuration and bootstrap
我们想让此部分简短。不幸的是,有多种不同的方法来配置和引导 Hibernate,并且我们不得不详细描述至少其中两种方法。
We would love to make this section short. Unfortunately, there’s several distinct ways to configure and bootstrap Hibernate, and we’re going to have to describe at least two of them in detail.
获取 Hibernate 实例的四种基本方法显示在下表中:
The four basic ways to obtain an instance of Hibernate are shown in the following table:
Using the standard JPA-defined XML, and the operation Persistence.createEntityManagerFactory() |
Usually chosen when portability between JPA implementations is important. |
Using the Configuration class to construct a SessionFactory |
When portability between JPA implementations is not important, this option is quicker, adds some flexibility and saves a typecast. |
Using the more complex APIs defined in org.hibernate.boot |
Used primarily by framework integrators, this option is outside the scope of this document. |
By letting the container take care of the bootstrap process and of injecting the SessionFactory or EntityManagerFactory |
Used in a container environment like WildFly or Quarkus. |
在这里,我们将重点关注前两种方法。
Here we’ll focus on the first two options.
如果您在容器环境外使用 Hibernate,则需要:
If you’re using Hibernate outside of a container environment, you’ll need to:
-
include Hibernate ORM itself, along with the appropriate JDBC driver, as dependencies of your project, and
-
configure Hibernate with information about your database, by specifying configuration properties.
2.1. Including Hibernate in your project build
首先,将以下依赖项添加到您的项目中:
First, add the following dependency to your project:
其中 {version} 是您使用的 Hibernate 版本。
Where {version} is the version of Hibernate you’re using.
您还需要为您的数据库添加 JDBC 驱动程序的依赖项。
You’ll also need to add a dependency for the JDBC driver for your database.
表 2. JDBC 驱动程序依赖项
Table 2. JDBC driver dependencies
Database |
Driver dependency |
PostgreSQL or CockroachDB |
org.postgresql:postgresql:{version} |
MySQL or TiDB |
com.mysql:mysql-connector-j:{version} |
MariaDB |
org.mariadb.jdbc:mariadb-java-client:{version} |
DB2 |
com.ibm.db2:jcc:{version} |
SQL Server |
com.microsoft.sqlserver:mssql-jdbc:${version} |
Oracle |
com.oracle.database.jdbc:ojdbc11:${version} |
H2 |
com.h2database:h2:{version} |
HSQLDB |
org.hsqldb:hsqldb:{version} |
其中 {version} 是您数据库的 JDBC 驱动程序的最新版本。
Where {version} is the latest version of the JDBC driver for your databse.
2.2. Optional dependencies
您还可以选择添加以下任何附加功能:
Optionally, you might also add any of the following additional features:
表 3. 可选依赖项
Table 3. Optional dependencies
Optional feature |
Dependencies |
An SLF4J logging implementation |
org.apache.logging.log4j:log4j-core or org.slf4j:slf4j-jdk14 |
A JDBC connection pool, for example, Agroal |
org.hibernate.orm:hibernate-agroal and io.agroal:agroal-pool |
The Hibernate Metamodel Generator, especially if you’re using the JPA criteria query API |
org.hibernate.orm:hibernate-processor |
The Query Validator, for compile-time checking of HQL |
org.hibernate:query-validator |
Hibernate Validator, an implementation of Bean Validation |
org.hibernate.validator:hibernate-validator and org.glassfish:jakarta.el |
Local second-level cache support via JCache and EHCache |
org.hibernate.orm:hibernate-jcache and org.ehcache:ehcache |
Local second-level cache support via JCache and Caffeine |
org.hibernate.orm:hibernate-jcache and com.github.ben-manes.caffeine:jcache |
Distributed second-level cache support via Infinispan |
org.infinispan:infinispan-hibernate-cache-v60 |
A JSON serialization library for working with JSON datatypes, for example, Jackson or Yasson |
com.fasterxml.jackson.core:jackson-databind or org.eclipse:yasson |
org.hibernate.orm:hibernate-spatial |
|
Envers, for auditing historical data |
org.hibernate.orm:hibernate-envers |
如果您希望使用 field-level lazy fetching,您还可以将 Hibernate bytecode enhancer 添加到 Gradle 构建中。
You might also add the Hibernate bytecode enhancer to your Gradle build if you want to use field-level lazy fetching.
2.3. Configuration using JPA XML
坚持使用 JPA 标准方法,我们将提供一个名为 persistence.xml 的文件,我们通常将其放在 persistence archive 的 META-INF 目录中,即包含我们的实体类的 .jar 文件或目录。
Sticking to the JPA-standard approach, we would provide a file named persistence.xml, which we usually place in the META-INF directory of a persistence archive, that is, of the .jar file or directory which contains our entity classes.
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence https://jakarta.ee/xml/ns/persistence/persistence_3_0.xsd"
version="2.0">
<persistence-unit name="org.hibernate.example">
<class>org.hibernate.example.Book</class>
<class>org.hibernate.example.Author</class>
<properties>
<!-- PostgreSQL -->
<property name="jakarta.persistence.jdbc.url"
value="jdbc:postgresql://localhost/example"/>
<!-- Credentials -->
<property name="jakarta.persistence.jdbc.user"
value="gavin"/>
<property name="jakarta.persistence.jdbc.password"
value="hibernate"/>
<!-- Automatic schema export -->
<property name="jakarta.persistence.schema-generation.database.action"
value="drop-and-create"/>
<!-- SQL statement logging -->
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.format_sql" value="true"/>
<property name="hibernate.highlight_sql" value="true"/>
</properties>
</persistence-unit>
</persistence>
<persistence-unit> 元素定义了一个命名的 persistence unit,即:
The <persistence-unit> element defines a named persistence unit, that is:
-
a collection of associated entity types, along with
-
a set of default configuration settings, which may be augmented or overridden at runtime.
每个 <class> 元素都指定一个实体类的完全限定名称。
Each <class> element specifies the fully-qualified name of an entity class.
每个 <property> 元素指定一个 configuration property 及其值。请注意:
Each <property> element specifies a configuration property and its value. Note that:
-
the configuration properties in the jakarta.persistence namespace are standard properties defined by the JPA spec, and
-
properties in the hibernate namespace are specific to Hibernate.
我们可以通过调用 Persistence.createEntityManagerFactory() 来获取 EntityManagerFactory:
We may obtain an EntityManagerFactory by calling Persistence.createEntityManagerFactory():
EntityManagerFactory entityManagerFactory =
Persistence.createEntityManagerFactory("org.hibernate.example");
如有必要,我们可以覆盖 persistence.xml 中指定的配置属性:
If necessary, we may override configuration properties specified in persistence.xml:
EntityManagerFactory entityManagerFactory =
Persistence.createEntityManagerFactory("org.hibernate.example",
Map.of(AvailableSettings.JAKARTA_JDBC_PASSWORD, password));
2.4. Configuration using Hibernate API
或者,它可以尊敬的类 Configuration 允许在 Java 代码中配置 Hibernate 实例。
Alternatively, the venerable class Configuration allows an instance of Hibernate to be configured in Java code.
SessionFactory sessionFactory =
new Configuration()
.addAnnotatedClass(Book.class)
.addAnnotatedClass(Author.class)
// PostgreSQL
.setProperty(AvailableSettings.JAKARTA_JDBC_URL, "jdbc:postgresql://localhost/example")
// Credentials
.setProperty(AvailableSettings.JAKARTA_JDBC_USER, user)
.setProperty(AvailableSettings.JAKARTA_JDBC_PASSWORD, password)
// Automatic schema export
.setProperty(AvailableSettings.JAKARTA_HBM2DDL_DATABASE_ACTION,
Action.SPEC_ACTION_DROP_AND_CREATE)
// SQL statement logging
.setProperty(AvailableSettings.SHOW_SQL, true)
.setProperty(AvailableSettings.FORMAT_SQL, true)
.setProperty(AvailableSettings.HIGHLIGHT_SQL, true)
// Create a new SessionFactory
.buildSessionFactory();
自最初(1.0 之前的版本)的 Hibernate 版本起,Configuration 类几乎保持不变,所以它看起来不太现代。另一方面,它非常易于使用,并展示了一些 persistence.xml 不支持的选项。
The Configuration class has survived almost unchanged since the very earliest (pre-1.0) versions of Hibernate, and so it doesn’t look particularly modern. On the other hand, it’s very easy to use, and exposes some options that persistence.xml doesn’t support.
2.5. Configuration using Hibernate properties file
如果我们使用 Hibernate Configuration API,但不想直接在 Java 代码中设置某些配置属性,可以在一个名为 hibernate.properties 的文件中指定它们,并将文件放入根类路径中。
If we’re using the Hibernate Configuration API, but we don’t want to put certain configuration properties directly in the Java code, we can specify them in a file named hibernate.properties, and place the file in the root classpath.
# PostgreSQL
jakarta.persistence.jdbc.url=jdbc:postgresql://localhost/example
# Credentials
jakarta.persistence.jdbc.user=hibernate
jakarta.persistence.jdbc.password=zAh7mY$2MNshzAQ5
# SQL statement logging
hibernate.show_sql=true
hibernate.format_sql=true
hibernate.highlight_sql=true
2.6. Basic configuration settings
类 AvailableSettings 枚举了 Hibernate 所理解的所有配置属性。
The class AvailableSettings enumerates all the configuration properties understood by Hibernate.
当然,我们不会在本教程中介绍所有有用的配置设置。我们将提一下你刚开始使用时需要的设置,稍后我们会回到其他重要设置,特别是在讨论性能调优的时候。
Of course, we’re not going to cover every useful configuration setting in this chapter. Instead, we’ll mention the ones you need to get started, and come back to some other important settings later, especially when we talk about performance tuning.
Hibernate 有很多(太多)开关和切换。请不要沉迷于调整这些设置;大多数设置很少需要,许多设置仅用于提供与较早版本的 Hibernate 的向后兼容性。除了少数例外情况,这些设置中的每一个的默认行为都被仔细选择以 the behavior we recommend。 |
Hibernate has many—too many—switches and toggles. Please don’t go crazy messing about with these settings; most of them are rarely needed, and many only exist to provide backward compatibility with older versions of Hibernate. With rare exception, the default behavior of every one of these settings was carefully chosen to be the behavior we recommend. |
真正需要了解的属性有以下三个:
The properties you really do need to get started are these three:
表 4。JDBC 连接设置
Table 4. JDBC connection settings
Configuration property name |
Purpose |
jakarta.persistence.jdbc.url |
JDBC URL of your database |
jakarta.persistence.jdbc.user and jakarta.persistence.jdbc.password |
Your database credentials |
在 Hibernate 6 中,不必指定 hibernate.dialect 。将自动为您确定正确的 Hibernate SQL Dialect 。指定此属性的唯一原因是您正在使用自定义的用户编写的 Dialect 类。
In Hibernate 6, you don’t need to specify hibernate.dialect. The correct Hibernate SQL Dialect will be determined for you automatically. The only reason to specify this property is if you’re using a custom user-written Dialect class.
同样,在使用所支持数据库之一时,也不需要 hibernate.connection.driver_class 或 jakarta.persistence.jdbc.driver 。
Similarly, neither hibernate.connection.driver_class nor jakarta.persistence.jdbc.driver is needed when working with one of the supported databases.
某些环境下,能够不访问数据库而启动 Hibernate 会很有用。在这种情况下,我们不仅必须明确指定数据库平台,还必须使用标准 JPA 配置属性指定数据库版本。
In some environments it’s useful to be able to start Hibernate without accessing the database. In this case, we must explicitly specify not only the database platform, but also the version of the database, using the standard JPA configuration properties.
# disable use of JDBC database metadata
hibernate.boot.allow_jdbc_metadata_access=false
# explicitly specify database and version
jakarta.persistence.database-product-name=PostgreSQL
jakarta.persistence.database-major-version=15
jakarta.persistence.database-minor-version=7
产品名是 java.sql.DatabaseMetaData.getDatabaseProductName() 返回的值,例如 PostgreSQL、MySQL、H2、Oracle、EnterpriseDB、MariaDB 或 Microsoft SQL Server。
The product name is the value returned by java.sql.DatabaseMetaData.getDatabaseProductName(), for example, PostgreSQL, MySQL H2, Oracle, EnterpriseDB, MariaDB, or Microsoft SQL Server.
表 5。数据库在启动时不可访问时需要的设置
Table 5. Settings needed when database is inaccessible at startup
Configuration property name |
Purpose |
hibernate.boot.allow_jdbc_metadata_access |
Set to false to disallow access to the database at startup |
jakarta.persistence.database-product-name |
The database product name, according to the JDBC driver |
jakarta.persistence.database-major-version and jakarta.persistence.database-minor-version |
The major and minor versions of the database |
池化 JDBC 连接是极其重要的一个性能优化设置。你可以使用此属性设置 Hibernate 内置连接池的大小:
Pooling JDBC connections is an extremely important performance optimization. You can set the size of Hibernate’s built-in connection pool using this property:
表 6。内置连接池大小
Table 6. Built-in connection pool size
Configuration property name |
Purpose |
hibernate.connection.pool_size |
The size of the built-in connection pool |
默认情况下,Hibernate 使用了功能简单的内置连接池。此池不是为产品用途而设计的,后面讨论性能时,我们将会介绍如何 select a more robust implementation 。
By default, Hibernate uses a simplistic built-in connection pool. This pool is not meant for use in production, and later, when we discuss performance, we’ll see how to select a more robust implementation.
或者,在容器环境中,至少需要以下某个属性:
Alternatively, in a container environment, you’ll need at least one of these properties:
表 7。事务管理设置
Table 7. Transaction management settings
Configuration property name |
Purpose |
jakarta.persistence.transactionType |
(Optional, defaults to JTA) Determines if transaction management is via JTA or resource-local transactions. Specify RESOURCE_LOCAL if JTA should not be used. |
jakarta.persistence.jtaDataSource |
JNDI name of a JTA datasource |
jakarta.persistence.nonJtaDataSource |
JNDI name of a non-JTA datasource |
在这种情况下,Hibernate 从一个容器管理的 DataSource 获取池化的 JDBC 数据库连接。
In this case, Hibernate obtains pooled JDBC database connections from a container-managed DataSource.
2.7. Automatic schema export
你可以让 Hibernate 从你在 Java 代码中指定的映射注释推断出你的数据库架构,并通过指定以下一个或多个配置属性在初始化时导出架构:
You can have Hibernate infer your database schema from the mapping annotations you’ve specified in your Java code, and export the schema at initialization time by specifying one or more of the following configuration properties:
表 8。架构管理设置
Table 8. Schema management settings
Configuration property name |
Purpose |
jakarta.persistence.schema-generation.database.action |
If drop-and-create, first drop the schema and then export tables, sequences, and constraintsIf create, export tables, sequences, and constraints, without attempting to drop them firstIf create-drop, drop the schema and recreate it on SessionFactory startup Additionally, drop the schema on SessionFactory shutdownIf drop, drop the schema on SessionFactory shutdownIf validate, validate the database schema without changing itIf update, only export what’s missing in the schema |
jakarta.persistence.create-database-schemas |
(Optional) If true, automatically create schemas and catalogs |
jakarta.persistence.schema-generation.create-source |
(Optional) If metadata-then-script or script-then-metadata, execute an additional SQL script when exported tables and sequences |
jakarta.persistence.schema-generation.create-script-source |
(Optional) The name of a SQL DDL script to be executed |
jakarta.persistence.sql-load-script-source |
(Optional) The name of a SQL DML script to be executed |
此特性对于测试极有帮助。
This feature is extremely useful for testing.
为数据库预先初始化测试或“引用”数据的最简单方法是将一系列 SQL insert 语句放到一个文件中,例如,import.sql,并使用属性 jakarta.persistence.sql-load-script-source 指定此文件的路径。我们刚才已经看过这种方法的 example ,它比编写 Java 代码实例化实体实例并为每个实例调用 persist() 更简洁。 |
The easiest way to pre-initialize a database with test or "reference" data is to place a list of SQL insert statements in a file named, for example, import.sql, and specify the path to this file using the property jakarta.persistence.sql-load-script-source. We’ve already seen an example of this approach, which is cleaner than writing Java code to instantiate entity instances and calling persist() on each of them. |
正如我们在 earlier 中提到的,控制架构导出也可以通过编程方式来实现。
As we mentioned earlier, it can also be useful to control schema export programmatically.
SchemaManager API 允许以编程方式控制 schema 导出: |
The SchemaManager API allows programmatic control over schema export: |
sessionFactory.getSchemaManager().exportMappedObjects(true); sessionFactory.getSchemaManager().exportMappedObjects(true); JPA 具有更有限且更不符合人体工程学的 API:
sessionFactory.getSchemaManager().exportMappedObjects(true); sessionFactory.getSchemaManager().exportMappedObjects(true); JPA has a more limited and less ergonomic API:
Persistence.generateSchema("org.hibernate.example", Map.of(JAKARTA_HBM2DDL_DATABASE_ACTION, CREATE)) Persistence.generateSchema("org.hibernate.example", Map.of(JAKARTA_HBM2DDL_DATABASE_ACTION, CREATE))
Persistence.generateSchema("org.hibernate.example", Map.of(JAKARTA_HBM2DDL_DATABASE_ACTION, CREATE)) Persistence.generateSchema("org.hibernate.example", Map.of(JAKARTA_HBM2DDL_DATABASE_ACTION, CREATE))
2.8. Logging the generated SQL
要查看发送到数据库的生成 SQL,你有两个选择。
To see the generated SQL as it’s sent to the database, you have two options.
一种方法是将属性 hibernate.show_sql 设置为 true,Hibernate 将把 SQL 直接记录到控制台。通过启用格式化或高亮显示,可以让输出更具可读性。这些设置在对生成 SQL 语句进行故障排除时非常有帮助。
One way is to set the property hibernate.show_sql to true, and Hibernate will log SQL direct to the console. You can make the output much more readable by enabling formatting or highlighting. These settings really help when troubleshooting the generated SQL statements.
表 9。记录 SQL 到控制台的设置
Table 9. Settings for SQL logging to the console
Configuration property name |
Purpose |
hibernate.show_sql |
If true, log SQL directly to the console |
hibernate.format_sql |
If true, log SQL in a multiline, indented format |
hibernate.highlight_sql |
If true, log SQL with syntax highlighting via ANSI escape codes |
或者,你可以使用首选的 SLF4J 日志实现,为类别 org.hibernate.SQL 启用调试级别日志记录。
Alternatively, you can enable debug-level logging for the category org.hibernate.SQL using your preferred SLF4J logging implementation.
例如,如果您使用 Log4J 2(如 Optional dependencies中所示),请将以下行添加到您的 log4j2.properties 文件中:
For example, if you’re using Log4J 2 (as above in Optional dependencies), add these lines to your log4j2.properties file:
# SQL execution
logger.hibernate.name = org.hibernate.SQL
logger.hibernate.level = debug
# JDBC parameter binding
logger.jdbc-bind.name=org.hibernate.orm.jdbc.bind
logger.jdbc-bind.level=trace
# JDBC result set extraction
logger.jdbc-extract.name=org.hibernate.orm.jdbc.extract
logger.jdbc-extract.level=trace
但采用这种方式,我们将错过漂亮的突出显示。
But with this approach we miss out on the pretty highlighting.
2.9. Minimizing repetitive mapping information
以下属性对于最大程度减少我们将在 Object/relational mapping 中讨论的 @Table 和 @Column 注释中需要明确指定的信息量非常有用:
The following properties are very useful for minimizing the amount of information you’ll need to explicitly specify in @Table and @Column annotations, which we’ll discuss below in Object/relational mapping:
表 10. 最小化显式映射信息的设置
Table 10. Settings for minimizing explicit mapping information
Configuration property name |
Purpose |
hibernate.default_schema |
A default schema name for entities which do not explicitly declare one |
hibernate.default_catalog |
A default catalog name for entities which do not explicitly declare one |
hibernate.physical_naming_strategy |
A PhysicalNamingStrategy implementing your database naming standards |
hibernate.implicit_naming_strategy |
An ImplicitNamingStrategy which specifies how "logical" names of relational objects should be inferred when no name is specified in annotations |
编写自己的 PhysicalNamingStrategy 和/或 ImplicitNamingStrategy 是一种特别有效的方法,它既可以减少实体类上的注解干扰,又可以实现数据库命名习惯,因此我们认为您应为每个非平凡数据模型执行此操作。我们将在 Naming strategies 中就此展开。 |
Writing your own PhysicalNamingStrategy and/or ImplicitNamingStrategy is an especially good way to reduce the clutter of annotations on your entity classes, and to implement your database naming conventions, and so we think you should do it for any nontrivial data model. We’ll have more to say about them in Naming strategies. |
2.10. Nationalized character data in SQL Server
By default, SQL Server 的 char 和 varchar 类型不适应 Unicode 数据。但是 Java 字符串可能包含任何 Unicode 字符。因此,如果您处理的是 SQL Server,您可能需要强制 Hibernate 使用 nchar 和 nvarchar 列类型。
By default, SQL Server’s char and varchar types don’t accommodate Unicode data. But a Java string may contain any Unicode character. So, if you’re working with SQL Server, you might need to force Hibernate to use the nchar and nvarchar column types.
表 11. 设置使用国际化字符数据
Table 11. Setting the use of nationalized character data
Configuration property name |
Purpose |
hibernate.use_nationalized_character_data |
Use nchar and nvarchar instead of char and varchar |
另一方面,如果只有 some 列存储国际化数据,则使用 @Nationalized 注释来表示实体的字段,这些字段映射这些列。
On the other hand, if only some columns store nationalized data, use the @Nationalized annotation to indicate fields of your entities which map these columns.
或者,您可以将 SQL Server 配置为使用启用了 UTF-8 的校对规则 _UTF8。 |
Alternatively, you can configure SQL Server to use the UTF-8 enabled collation _UTF8. |