Hibernate ORM 中文操作指南
2. Configuration and bootstrap
我们想让此部分简短。不幸的是,有多种不同的方法来配置和引导 Hibernate,并且我们不得不详细描述至少其中两种方法。
获取 Hibernate 实例的四种基本方法显示在下表中:
使用标准 JPA 定义的 XML 和操作 Persistence.createEntityManagerFactory() |
通常在 JPA 实现之间的可移植性很重要时选择。 |
使用 Configuration 类构造 SessionFactory |
如果跨 JPA 实现的可移植性不重要,此选项则更快、增加了些许灵活性并节省类型转换。 |
使用 org.hibernate.boot 中定义的更复杂的 API |
此选项主要由框架集成器使用,不在本文档的讨论范围之内。 |
让容器负责引导过程并注入 SessionFactory 或 EntityManagerFactory |
用在 WildFly 或 Quarkus 等容器环境中。 |
在这里,我们将重点关注前两种方法。
如果您在容器环境外使用 Hibernate,则需要:
-
在你的项目中包含 Hibernate ORM 本身和合适的 JDBC 驱动程序作为依赖项,并且
-
通过指定配置属性,使用有关你的数据库的信息配置 Hibernate。
2.1. Including Hibernate in your project build
首先,将以下依赖项添加到您的项目中:
其中 {version} 是您使用的 Hibernate 版本。
您还需要为您的数据库添加 JDBC 驱动程序的依赖项。
表 2. JDBC 驱动程序依赖项
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 驱动程序的最新版本。
2.2. Optional dependencies
您还可以选择添加以下任何附加功能:
表 3. 可选依赖项
Optional feature |
Dependencies |
An SLF4J logging implementation |
org.apache.logging.log4j:log4j-core or org.slf4j:slf4j-jdk14 |
JDBC 连接池,例如 Agroal |
org.hibernate.orm:hibernate-agroal and io.agroal:agroal-pool |
Hibernate Metamodel Generator,尤其是当您使用 JPA 标准查询 API 时 |
org.hibernate.orm:hibernate-processor |
Query Validator,用于对 HQL 进行编译时检查 |
org.hibernate:query-validator |
org.hibernate.validator:hibernate-validator and org.glassfish:jakarta.el |
|
通过 JCache 和 EHCache提供本地二级缓存支持 |
org.hibernate.orm:hibernate-jcache and org.ehcache:ehcache |
通过 JCache 和 Caffeine提供本地二级缓存支持 |
org.hibernate.orm:hibernate-jcache and com.github.ben-manes.caffeine:jcache |
通过 Infinispan提供分布式二级缓存支持 |
org.infinispan:infinispan-hibernate-cache-v60 |
com.fasterxml.jackson.core:jackson-databind or org.eclipse:yasson |
|
org.hibernate.orm:hibernate-spatial |
|
Envers,用于审计历史数据 |
org.hibernate.orm:hibernate-envers |
如果您希望使用 field-level lazy fetching,您还可以将 Hibernate bytecode enhancer 添加到 Gradle 构建中。
2.3. Configuration using JPA XML
坚持使用 JPA 标准方法,我们将提供一个名为 persistence.xml 的文件,我们通常将其放在 persistence archive 的 META-INF 目录中,即包含我们的实体类的 .jar 文件或目录。
<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,即:
-
一组关联的实体类型,以及
-
一组默认配置设置,可在运行时增加或覆盖。
每个 <class> 元素都指定一个实体类的完全限定名称。
每个 <property> 元素指定一个 configuration property 及其值。请注意:
-
jakarta.persistence 命名空间中的配置属性是 JPA 规范定义的标准属性,并且
-
hibernate 命名空间中的属性是 Hibernate 特有的。
我们可以通过调用 Persistence.createEntityManagerFactory() 来获取 EntityManagerFactory:
EntityManagerFactory entityManagerFactory =
Persistence.createEntityManagerFactory("org.hibernate.example");
如有必要,我们可以覆盖 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 实例。
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 不支持的选项。
2.5. Configuration using Hibernate properties file
如果我们使用 Hibernate Configuration API,但不想直接在 Java 代码中设置某些配置属性,可以在一个名为 hibernate.properties 的文件中指定它们,并将文件放入根类路径中。
# 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 所理解的所有配置属性。
当然,我们不会在本教程中介绍所有有用的配置设置。我们将提一下你刚开始使用时需要的设置,稍后我们会回到其他重要设置,特别是在讨论性能调优的时候。
Hibernate 有很多(太多)开关和切换。请不要沉迷于调整这些设置;大多数设置很少需要,许多设置仅用于提供与较早版本的 Hibernate 的向后兼容性。除了少数例外情况,这些设置中的每一个的默认行为都被仔细选择以 the behavior we recommend。 |
真正需要了解的属性有以下三个:
表 4。JDBC 连接设置
Configuration property name |
Purpose |
jakarta.persistence.jdbc.url |
数据库的 JDBC URL |
jakarta.persistence.jdbc.user and jakarta.persistence.jdbc.password |
Your database credentials |
在 Hibernate 6 中,不必指定 hibernate.dialect 。将自动为您确定正确的 Hibernate SQL Dialect 。指定此属性的唯一原因是您正在使用自定义的用户编写的 Dialect 类。
同样,在使用所支持数据库之一时,也不需要 hibernate.connection.driver_class 或 jakarta.persistence.jdbc.driver 。
某些环境下,能够不访问数据库而启动 Hibernate 会很有用。在这种情况下,我们不仅必须明确指定数据库平台,还必须使用标准 JPA 配置属性指定数据库版本。
# 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。
表 5。数据库在启动时不可访问时需要的设置
Configuration property name |
Purpose |
hibernate.boot.allow_jdbc_metadata_access |
设置为 false 在启动时禁止访问数据库 |
jakarta.persistence.database-product-name |
根据 JDBC 驱动程序,数据库的产品名称 |
jakarta.persistence.database-major-version and jakarta.persistence.database-minor-version |
数据库的主次版本 |
池化 JDBC 连接是极其重要的一个性能优化设置。你可以使用此属性设置 Hibernate 内置连接池的大小:
表 6。内置连接池大小
Configuration property name |
Purpose |
hibernate.connection.pool_size |
内置连接池的大小 |
默认情况下,Hibernate 使用了功能简单的内置连接池。此池不是为产品用途而设计的,后面讨论性能时,我们将会介绍如何 select a more robust implementation 。
或者,在容器环境中,至少需要以下某个属性:
表 7。事务管理设置
Configuration property name |
Purpose |
jakarta.persistence.transactionType |
(可选的,默认为 JTA)确定事务管理是通过 JTA 还是资源本地事务。如果 JTA 不应使用,则指定 RESOURCE_LOCAL。 |
jakarta.persistence.jtaDataSource |
JTA 数据源的 JNDI 名称 |
jakarta.persistence.nonJtaDataSource |
非 JTA 数据源的 JNDI 名称 |
在这种情况下,Hibernate 从一个容器管理的 DataSource 获取池化的 JDBC 数据库连接。
2.7. Automatic schema export
你可以让 Hibernate 从你在 Java 代码中指定的映射注释推断出你的数据库架构,并通过指定以下一个或多个配置属性在初始化时导出架构:
表 8。架构管理设置
Configuration property name |
Purpose |
jakarta.persistence.schema-generation.database.action |
如果 drop-and-create,首先放弃架构,然后导出表格、序列和其他约束如果 create,导出表格、序列和其他约束,而没有尝试在首先放弃它们如果 create-drop,放弃架构,并在 SessionFactory 启动时重新创建它另外,在 SessionFactory 关机时放弃架构如果 drop,在 SessionFactory 关机时放弃架构如果 validate,验证数据库架构,而无需更改如果 update,仅导出架构中的缺失内容 |
jakarta.persistence.create-database-schemas |
(可选的)如果 true,自动创建架构和目录 |
jakarta.persistence.schema-generation.create-source |
(可选的)如果 metadata-then-script 或 script-then-metadata,在导出的表格和序列时执行附加的 SQL 脚本 |
jakarta.persistence.schema-generation.create-script-source |
(可选的)要执行的 SQL DDL 脚本的名称 |
jakarta.persistence.sql-load-script-source |
(可选)要执行的 SQL DML 脚本的名称 |
此特性对于测试极有帮助。
为数据库预先初始化测试或“引用”数据的最简单方法是将一系列 SQL insert 语句放到一个文件中,例如,import.sql,并使用属性 jakarta.persistence.sql-load-script-source 指定此文件的路径。我们刚才已经看过这种方法的 example ,它比编写 Java 代码实例化实体实例并为每个实例调用 persist() 更简洁。 |
正如我们在 earlier 中提到的,控制架构导出也可以通过编程方式来实现。
SchemaManager API 允许以编程方式控制 schema 导出: |
sessionFactory.getSchemaManager().exportMappedObjects(true); sessionFactory.getSchemaManager().exportMappedObjects(true); JPA 具有更有限且更不符合人体工程学的 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))
2.8. Logging the generated SQL
要查看发送到数据库的生成 SQL,你有两个选择。
一种方法是将属性 hibernate.show_sql 设置为 true,Hibernate 将把 SQL 直接记录到控制台。通过启用格式化或高亮显示,可以让输出更具可读性。这些设置在对生成 SQL 语句进行故障排除时非常有帮助。
表 9。记录 SQL 到控制台的设置
Configuration property name |
Purpose |
hibernate.show_sql |
如果指定 true,将直接将 SQL 记录到控制台中 |
hibernate.format_sql |
如果指定 true,将以多行缩进格式记录 SQL |
hibernate.highlight_sql |
如果指定 true,将通过 ANSI 转义代码将 SQL 与语法高亮一起记录 |
或者,你可以使用首选的 SLF4J 日志实现,为类别 org.hibernate.SQL 启用调试级别日志记录。
例如,如果您使用 Log4J 2(如 Optional dependencies中所示),请将以下行添加到您的 log4j2.properties 文件中:
# 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
但采用这种方式,我们将错过漂亮的突出显示。
2.9. Minimizing repetitive mapping information
以下属性对于最大程度减少我们将在 Object/relational mapping 中讨论的 @Table 和 @Column 注释中需要明确指定的信息量非常有用:
表 10. 最小化显式映射信息的设置
Configuration property name |
Purpose |
hibernate.default_schema |
没有明确声明的实体的默认模式名称 |
hibernate.default_catalog |
没有明确声明的实体的默认目录名称 |
hibernate.physical_naming_strategy |
一个 PhysicalNamingStrategy,用于实施数据库命名标准 |
hibernate.implicit_naming_strategy |
一个 ImplicitNamingStrategy,用于指定未在注释中指定名称时如何推断关系对象的“逻辑”名称 |
编写自己的 PhysicalNamingStrategy 和/或 ImplicitNamingStrategy 是一种特别有效的方法,它既可以减少实体类上的注解干扰,又可以实现数据库命名习惯,因此我们认为您应为每个非平凡数据模型执行此操作。我们将在 Naming strategies 中就此展开。 |
2.10. Nationalized character data in SQL Server
By default, SQL Server 的 char 和 varchar 类型不适应 Unicode 数据。但是 Java 字符串可能包含任何 Unicode 字符。因此,如果您处理的是 SQL Server,您可能需要强制 Hibernate 使用 nchar 和 nvarchar 列类型。
表 11. 设置使用国际化字符数据
Configuration property name |
Purpose |
hibernate.use_nationalized_character_data |
使用 nchar 和 nvarchar,而不是 char 和 varchar |
另一方面,如果只有 some 列存储国际化数据,则使用 @Nationalized 注释来表示实体的字段,这些字段映射这些列。
或者,您可以将 SQL Server 配置为使用启用了 UTF-8 的校对规则 _UTF8。 |