开发 Hibernate 应用程序

Red Hat JBoss Enterprise Application Platform 7.3

面向希望开发和部署 Jakarta Persistence API(JPA)或 Hibernate 应用程序以用于红帽 JBoss 企业应用平台的开发人员和管理员的说明和信息。

摘要

本文档为希望使用红帽 JBoss 企业应用平台开发和部署 Jakarta Persistence 或 Hibernate 应用程序的开发人员和管理员提供了信息。

第 1 章 简介

1.1. 关于 Hibernate 内核

Hibernate Core 是 Java 语言的对象关系映射框架。它提供了一个将面向对象的域模型映射到关系数据库的框架,允许应用避免直接与数据库交互。Hibernate 通过用高级别对象处理功能替代直接持久数据库访问,解决对象关系不匹配问题。

1.2. Hibernate EntityManager

Hibernate 实体管理器实施由 Jakarta Persistence 2.2 规范定义的编程接口和生命周期规则。此打包程序与 Hibernate 批注一起,在成熟的 Hibernate 核心基础上实施独立的 Jakarta Persistence 解决方案。您可以组合使用所有三个组件、不带 Jakarta Persistence 编程接口和生命周期的注释,甚至还可以根据项目的业务和技术需求使用纯原生 Hibernate 内核。您随时可以回退到 Hibernate 原生 API,或者在需要时甚至退回到原生 JDBC 和 SQL。它为 JBoss EAP 提供了完整的 Jakarta Persistence 解决方案。

JBoss EAP 的 7.3 发行版本符合 Jakarta Persistence 2.2 规范,其符合 Jakarta EE 8 中定义的规范

Hibernate 还提供规范的其他功能。若要开始使用 Jakarta Persistence 和 JBoss EAP,请参阅 JBoss EAP 附带的 bean-validation、gleter 和 Kitchen sink 快速入门。

Jakarta Persistence 在容器中(如 Jakarta Enterprise Beans 3 或更现代化的 Jakarta Contexts 和 Dependency Injection)以及独立 Java SE 应用在特定容器外执行。两种环境中都提供以下编程接口和构件:

重要

如果您计划将安全管理器与 Hibernate 一起使用,请注意,Hibernate 仅在 JBoss EAP 服务器引导 实体管理器Factory 时支持它。当应用程序引导 EntityManagerFactorySessionFactory 时不支持它。

EntityManagerFactory
实体管理器工厂提供实体管理器实例,所有实例都配置为连接到同一数据库,使用由特定实施定义的相同默认设置等。您可以准备多个实体管理器工厂来访问多个数据存储。此界面与原生 Hibernate 中的 SessionFactory 类似。
EntityManager
实体管理器 API 用于访问特定工作单元中的数据库。它用于创建和删除持久实体实例,按主要密钥身份查找实体,以及对所有实体进行查询。此界面与 Hibernate 中的 Session 类似。
持久性上下文
持久上下文是一组实体实例,其中任何持久实体身份都有唯一的实体实例。在持久上下文中,实体实例及其生命周期由特定实体管理器管理。此上下文的范围可以是事务,也可以是扩展工作单元。
persistence 单元
可由给定实体管理器管理的实体类型集合由持久性单元定义。持久性单元定义应用相关或分组的所有类的集合,它们在映射到单个数据存储时必须共存。
容器管理的实体管理器
生命周期由容器管理的实体管理器。
应用程序管理的实体管理器
生命周期由应用程序管理的实体管理器。
Jakarta Transactions 实体经理
参与雅加达交易的实体经理.
资源本地实体管理器
使用资源交易(而不是 Jakarta 交易)的实体管理器。

第 2 章 Hibernate 配置

2.1. Hibernate 配置

应用服务器内和独立应用中实体管理器的配置都位于持久存档中。持久存档是一种 JAR 文件,必须定义驻留在 META-INF/ 文件夹中的 persistence.xml 文件。

您可以使用 persistence.xml 文件连接数据库。有两种方法可以做到这一点:

  • 指定 JBoss EAP 的 datasources 子系统中配置的数据源。

    jta-data-source 指向此持久性单元映射到的数据源的 Java 命名和目录接口名称。java:jboss/datasources/ExampleDS 此处指向 JBoss EAP 中嵌入的 H2 DB

    persistence.xml 文件中的 object-relational-mapping 示例

    <persistence>
       <persistence-unit name="myapp">
          <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
          <jta-data-source>java:jboss/datasources/ExampleDS</jta-data-source>
          <properties>
             ... ...
          </properties>
       </persistence-unit>
    </persistence>

  • 通过指定连接属性,显式配置 persistence.xml 文件。

    persistence.xml 文件中指定连接属性示例

    <property name="javax.persistence.jdbc.driver" value="org.hsqldb.jdbcDriver"/>
    <property name="javax.persistence.jdbc.user" value="sa"/>
    <property name="javax.persistence.jdbc.password" value=""/>
    <property name="javax.persistence.jdbc.url" value="jdbc:hsqldb:."/>

    有关连接属性的完整列表,请参阅 persistence.xml 文件中可配置的连接属性。

有许多属性控制 Hibernate 在运行时的行为。所有都是可选的,且具有合理的默认值。这些 Hibernate 属性均在 persistence.xml 文件中使用。有关所有可配置 Hibernate 属性的完整列表,请参阅 Hibernate Properties

2.2. 第二级缓存

2.2.1. 关于第二级缓存

第二级缓存是在应用会话外保留信息的本地数据存储。缓存由持久性提供商管理,通过将数据与应用分开来改进运行时。

JBoss EAP 支持用于以下目的的缓存:

  • Web Session Clustering
  • 有状态的 Session Bean Clustering
  • SSO 集群
  • Hibernate 第二级缓存
  • Jakarta Persistence second-level Cache
警告

每个缓存容器定义一个 repl 和一个 dist 缓存。用户应用不应直接使用这些缓存。

2.2.2. 为 Hibernate 配置二级缓存

可以通过两种方式进行 Infinispan 配置为 Hibernate 的二级缓存:

使用 Hibernate 原生应用程序配置 Hibernate 的第二级缓存
  1. 在部署的类路径中创建 hibernate.cfg.xml 文件。
  2. 将以下 XML 添加到 hibernate.cfg.xml 文件中:XML 需要位于 <session-factory> 标签中:

    <property name="hibernate.cache.use_second_level_cache">true</property>
    <property name="hibernate.cache.use_query_cache">true</property>
    <property name="hibernate.cache.region.factory_class">org.jboss.as.jpa.hibernate5.infinispan.InfinispanRegionFactory</property>
  3. 要在应用程序中使用 Hibernate 原生 API,您必须在 MANIFEST.MF 文件中添加以下依赖项:

    Dependencies: org.infinispan,org.hibernate

第 3 章 Hibernate 标注

3.1. Hibernate 标注

org.hibernate.annotations 软件包包含在标准 Jakarta Persistence 注释之上,由 Hibernate 提供的一些注释。

表 3.1. 常规注解

注解描述

检查

可以在类、属性或集合级别上定义的任意 SQL 检查限制。

不可变

将实体或集合标记为不可变。无注释表示该元素是可变的。

不可变实体可能不会由应用更新。不可变实体的更新将被忽略,但不会抛出异常。

集合上放置 的 @immutable 使集合不可变,这意味着不允许向集合中添加和删除。在这种情况下,将抛出 HibernateException

表 3.2. 缓存实体

注解描述

cache

向 root 实体或集合添加缓存策略。

表 3.3. 集合相关注解

注解描述

MapKeyType

定义永久映射的密钥类型。

ManyToAny

定义指向不同实体类型的 ToMany 关联。匹配实体类型是通过元数据磁盘列实现的。此类映射应该只有很少的映射。

OrderBy

使用 SQL 排序(而非 HQL 排序)订购集合。

OnDelete

用于集合、数组和接合子类的策略。目前不支持次要表的 OnDelete

Persister

指定自定义持久化器。

排序

集合排序(Java 级别排序)。

其中

其中,要添加到集合的元素实体或目标实体的子句。子句使用 SQL 编写。

WhereJoinTable

其中,要添加到集合连接表的子句。子句使用 SQL 编写。

表 3.4. CRUD Operations 的自定义 SQL

注解描述

loader

覆盖 Hibernate 默认 FIND 方法.

SQLDelete

覆盖 Hibernate 默认 DELETE 方法。

SQLDeleteAll

覆盖 Hibernate 默认 DELETE ALL 方法。

SQLInsert

覆盖 Hibernate 默认 INSERT INTO 方法。

SQLUpdate

覆盖 Hibernate 默认 UPDATE 方法。

Subselect

将不可变和只读实体映射到给定 SQL 子选择表达式。

synchronize

确保自动清空正确,并且对派生实体的查询不会返回过时的数据。主要用于 Subselect.

表 3.5. 实体

注解描述

cascade

对关联应用级联战略。

实体

添加可能需要超过标准 @Entity 中定义的元数据。

  • 可变 :此实体是否可更改
  • dynamicInsert :允许动态 SQL 进行插入
  • dynamicUpdate :允许动态 SQL 进行更新
  • selectBeforeUpdate :指定 Hibernate 不应执行 SQL UPDATE,除非确定实际修改了某个对象。
  • 多形图 :实体多形体是 PolymorphismType.IMPLICIT(默认)还是 PolymorphismType.EXPLICIT
  • 中立地: 开放式锁定策略(OptimisticLockType.VERSION、OptimisticLockType.NONE、OptimisticLockType.DIRTY 或 OptimisticLockType.ALL)

    注意

    注解"Entity"已弃用,并计划在以后的版本中删除。其独立属性或值应当成为注释。

Polymorphism

用于定义多形 Hibernate 的类型适用于实体层次结构。

Proxy

特定类的 lazy 和代理配置。

表的补充信息,可以是主要或次要信息。

表的复数注释.

目标

定义明确的目标,避免误会和通用解决方案。

Tuplizer

为实体或组件定义导体。

Tuplizers

为实体或组件定义一组教学程序。

表 3.6. 获取

注解描述

BatchSize

用于 SQL 加载的批处理大小.

FetchProfile

定义获取策略配置文件。

FetchProfiles

@FetchProfile 的复数注释.

LazyGroup

指定应当获取实体属性以及属于同一组的所有其他属性。为了加载实体属性 lazily,需要进行字节代码增强。默认情况下,所有非收集属性都会加载到一个名为 DEFAULT 的组中。此注释允许在访问组中的一个属性时一起初始化不同的属性组。

表 3.7. 过滤器

注解描述

filter

向集合的实体或目标实体添加过滤器。

FilterDef

过滤定义.

FilterDefs

过滤器定义数组。

FilterJoinTable

为连接表集合添加过滤器。

FilterJoinTables

将多个 @FilterJoinTable 添加到集合中。

过滤器

添加多个 @Filter.

ParamDef

参数定义。

表 3.8. 主密钥

注解描述

generated

此注释的属性由数据库生成。

GenericGenerator

以取消输入的方式描述任何类型的 Hibernate 生成器的生成器注释。

GenericGenerators

通用生成器定义的数组。

NaturalId

指定属性是实体的自然 ID 的一部分。

参数

键/值模式.

RowId

支持 Hibernate 的 ROWID 映射功能.

表 3.9. 继承

注解描述

DiscriminatorFormula

将要放置在根实体上的磁盘公式。

DiscriminatorOptions

用于表达 Hibernate 特定磁盘属性的可选注释。

MetaValue

将给定的分级值映射到对应的实体类型。

表 3.10. 映射 JP-QL/HQL Queries

注解描述

NamedNativeQueries

扩展 NamedNativeQueries 以存放 Hibernate NamedNativeQuery 对象.

NamedNativeQuery

使用 Hibernate 功能扩展 NamedNativeQuery.

NamedQueries

扩展 NamedQueries 以存放 Hibernate NamedQuery 对象。

NamedQuery

使用 Hibernate 功能扩展 NamedQuery.

表 3.11. 映射简单属性

注解描述

AccessType

属性访问类型.

支持一组列.对于组件用户类型映射很有用。

ColumnTransformer

用于从 中读取值并将值写入列的自定义 SQL 表达式。使用 直接加载/保存对象以及查询。写入表达式必须只包含一个值的 '?' 占位符。

ColumnTransformers

@ColumnTransformer 的复数注释.当超过一列正在使用此行为时,非常有用。

表 3.12. 属性

注解描述

公式

在大多数地方用作 @Column 的替代品.公式必须是有效的 SQL 片段。

index

定义数据库索引。

JoinFormula

可用于替换大多数位置的 @JoinColumn。公式必须是有效的 SQL 片段。

父级

将属性作为指针引用给所有者(通常是自有实体)。

类型

Hibernate 类型.

TypeDef

Hibernate 类型定义.

TypeDefs

Hibernate 类型定义数组.

表 3.13. 单个关联备注

注解描述

任意

定义指向多个实体类型的 ToOne 关联。与按实体类型匹配是通过元数据磁盘列实现的。此类映射应该只有很少的映射。

AnyMetaDef

定义 @Any@ManyToAny 元数据.

AnyMetaDefs

定义 @Any@ManyToAny 组元数据.可以在实体级别或软件包级别上定义。

获取

定义用于给定关联的 fetching 策略。

LazyCollection

定义集合的延迟状态。

LazyToOne

定义 ToOne 关联(即 OneToOne 或 ManyToOne )的 宽度状态。

NotFound

关联上找不到某一元素时要执行的操作.

表 3.14. 静止的锁定

注解描述

OptimisticLock

注释的属性更改将触发实体版本递增。如果没有该注释,该属性将涉及开放式锁定策略(默认)。

OptimisticLocking

用于定义应用于实体的开放式锁定方式。在层次结构中,仅在 root 实体上有效。

Source

可选注解与 Version 和时间戳版本属性组合。注解值决定时间戳的生成位置。

第 4 章 Hibernate 查询语言

4.1. 关于 Hibernate 查询语言

Java Persistence 查询语言简介

Java Persistence 查询语言是一种独立于平台的对象导向查询语言,定义为 Java Persistence API 规范的一部分。Jakarta 等效于 Java Persistence 查询语言是 Jakarta Persistence 查询语言,它被定义为 Jakarta Persistence 规范的一部分

Java Persistence 查询语言用于对存储在关系数据库中的实体进行查询。它受到 SQL 的极大启发,其查询语法类似于 SQL 查询,但针对 Java Persistence API 实体对象运行,而不是直接使用数据库表。

HQL 简介

Hibernate 查询语言(HQL)是一个功能强大的查询语言,类似于 SQL。但是,与 SQL 相比,HQL 完全面向对象,并且理解继承、多形性和关联等概念。

HQL 是 Java Persistence 查询语言的超集。HQL 查询并不总是是一个有效的 Java Persistence 查询语言查询,但 Java Persistence 查询语言查询始终是有效的 HQL 查询。

HQL 和 Java Persistence 查询语言都不是执行查询操作的非类型安全方法。标准查询提供了用于查询的类型安全方法。

4.2. 关于 HQL 语句

HQL 和 Java Persistence 查询语言都允许 SELECTUPDATE 和 DELETE 语句。HQL 还允许 INSERT 语句,其格式类似于 SQL INSERT-SELECT

下表显示了各种 HQL 语句的 Backus-Naur Form(BNF)表示法中的语法。

表 4.1. HQL 语句

声明描述

SELECT

HQL 中用于 SELECT 语句的 BNF 是:

select_statement :: =
        [select_clause]
        from_clause
        [where_clause]
        [groupby_clause]
        [having_clause]
        [orderby_clause]

UPDATE

HQL 中的 UPDATE 语句与 Java Persistence 查询语言相同。

update_statement ::= update_clause [where_clause]

update_clause ::= UPDATE entity_name [[AS] identification_variable]
        SET update_item {, update_item}*

update_item ::= [identification_variable.]{state_field | single_valued_object_field}
        = new_value

new_value ::= scalar_expression |
                simple_entity_expression |
                NULL

删除

HQL 中的 DELETE 语句的 BNF 与 Java Persistence 查询语言相同。

delete_statement ::= delete_clause [where_clause]

delete_clause ::= DELETE FROM entity_name [[AS] identification_variable]

INSERT

HQL 中的 INSERT 语句的 BNF 是:

insert_statement ::= insert_clause select_statement

insert_clause ::= INSERT INTO entity_name (attribute_list)

attribute_list ::= state_field[, state_field ]*

没有与它对应的 Java Persistence 查询语言。

警告

Hibernate 允许使用数据操作语言(DML)直接通过 Hibernate 查询语言(HQL)批量插入、更新和删除数据。

使用 DML 可能会违反对象/关系映射,并可能会影响对象状态。对象状态保留在内存中,使用 DML 时,内存中对象的状态不受影响,具体取决于对底层数据库执行的操作。如果使用 DML,则必须小心使用内存中数据。

关于 UPDATE 和 DELETE 语句

UPDATE 和 DELETE 语句的伪syntax 是:

(更新 | 从中删除 )EntityName(WHERE where_conditions)?

注意

FROM 关键字和 WHERE 术语是可选的。FROM 子句负责定义可供查询的其余部分使用的对象模型类型的范围。它还负责定义其余查询可用的所有标识变量。WHERE 子句允许您优化返回的实例列表。

执行 UPDATEDELETE 语句的结果是实际受影响的行数(更新或删除)。

示例:批量更新语句

Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();

String hqlUpdate = "update Company set name = :newName where name = :oldName";
int updatedEntities = s.createQuery( hqlUpdate )
        .setString( "newName", newName )
        .setString( "oldName", oldName )
        .executeUpdate();
tx.commit();
session.close();

示例:批量删除语句

Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();

String hqlDelete = "delete Company where name = :oldName";
int deletedEntities = s.createQuery( hqlDelete )
        .setString( "oldName", oldName )
        .executeUpdate();
tx.commit();
session.close();

Query.executeUpdate() 方法返回的 int 值指示受操作影响的数据库内实体数量。

在内部,数据库可能会使用多个 SQL 语句来执行响应 DML 更新 或删除 请求 的操作。这可能是因为表和需要更新或删除的连接表之间存在关系。

例如,如上例所示,发出删除声明可能实际上不仅对使用 oldName 命名的 公司的 Company 表执行删除,而且会对合并表执行删除。因此 由于 成功执行了上例,与 Employee 表的双向多对多关系也会从相应的加入表中丢弃行。

已删除的Entries 值包含操作影响的所有行的计数,包括 join 表中的行。

重要

执行批量更新或删除操作时应小心,因为它们可能会导致数据库和活动持久化上下文中的实体不一致。通常,批量更新和删除操作应只在新持久性上下文中的事务内执行,或者在获取或访问状态可能受到此类操作影响的实体之前执行。

关于 INSERT 语句

HQL 添加了定义 INSERT 语句的功能。没有与它对应的 Java Persistence 查询语言。HQL INSERT 语句的 Backus-Naur Form(BNF)是:

insert_statement ::= insert_clause select_statement

insert_clause ::= INSERT INTO entity_name (attribute_list)

attribute_list ::= state_field[, state_field ]*

attribute_list 与 SQL INSERT 语句中的列规格类似。对于涉及映射继承的实体,在 properties _list 中只能使用直接在指定实体上定义的属性。不允许超级类属性,子类属性并不合理。换句话说,INSERT 语句本质上是非私有的。

警告

select_statement 可以是任何有效的 HQL 选择查询,注意返回类型必须与插入预期的类型匹配。目前,这会在查询编译过程中检查,而不是让检查与数据库相连接。这可能会导致 Hibernate 类型与相等的问题 例如,这可能会导致映射为 org.hibernate.type.DateType 的属性和定义为 org.hibernate.type.TimestampType 的属性之间不匹配问题,即使数据库可能无法区分或处理转换。

对于 id 属性,插入语句为您提供两个选项:您可以在 attribute_list 中明确指定 id 属性,在这种情况下,从对应的 select 表达式获取它的值,或者从 attribute_list 中省略它,在这种情况下使用生成的值。只有使用"在数据库中操作"的 id 生成器时才可使用后一种选项;尝试将此选项用于任何"内存中"类型生成器将导致解析过程中出现异常情况。

对于不确定的锁定属性,插入语句再次为您提供两个选项:您可以在 attribute_list 中指定 属性,在这种情况下,它的值取自对应的选择表达式,或者从 attribute_list 中省略它,在这种情况下,使用了对应的 org.hibernate.type.VersionType 定义的 seed 值

示例:INSERT 查询语句

String hqlInsert = "insert into DelinquentAccount (id, name) select c.id, c.name from Customer c where ...";
int createdEntities = s.createQuery(hqlInsert).executeUpdate();

示例: Bulkert Statement

Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();

String hqlInsert = "insert into Account (id, name) select c.id, c.name from Customer c where ...";
int createdEntities = s.createQuery( hqlInsert )
        .executeUpdate();
tx.commit();
session.close();

如果不使用 SELECT 语句提供 id 属性的值,则会为您生成标识符,只要底层数据库支持自动生成的密钥。此批量插入操作的返回值是数据库中实际创建的条目数。

4.3. 关于 HQL 排序

查询的结果也可以排序。ORDER BY 子句用于指定用于排序结果的选定值。作为按顺序子句的一部分,表达式的类型被视为有效,包括:

  • 状态字段
  • 组件/嵌入式属性
  • 星形表达式,如算术运算、函数等。
  • 在 select 子句中为任一表达式类型声明的标识变量

HQL 不强制在 select 子句中命名排序句中引用的所有值,但它需要 Java Persistence 查询语言。代表数据库可移植性的应用程序应该意识到,并非所有数据库都支持在 select 子句中引用未引用的顺序子句中的值。

排序中的各个表达式可以通过 ASC (发送)或 DESC (降序)来指示所需的排序方向。

示例:订单人

// legal because p.name is implicitly part of p
select p
from Person p
order by p.name

select c.id, sum( o.total ) as t
from Order o
    inner join o.customer c
group by c.id
order by t

4.4. 关于集合成员参考

引用集合值的关联实际上指的是该集合的值

示例:集合参考

select c
from Customer c
    join c.orders o
    join o.lineItems l
    join l.product p
where o.status = 'pending'
  and p.status = 'backorder'

// alternate syntax
select c
from Customer c,
    in(c.orders) o,
    in(o.lineItems) l
    join l.product p
where o.status = 'pending'
  and p.status = 'backorder'

在这个示例中,标识变量 o 实际指的是对象模型类型顺序,这是客户#顺序关联元素的类型。

示例还显示了使用 IN 语法指定集合关联接合的替代语法。两种形式都是等同的。哪种应用程序选择使用就只是一个体验问题。

4.5. 关于限定路径表达式

之前已指出收集值的关联实际指的是该集合的值。根据集合的类型,也提供一组明确的资格表达式。

表 4.2. 路径表达式

expression描述

VALUE

指的是集合值。与未指定限定符相同。用于明确显示意图.对任何类型的 collection-valued 引用有效。

INDEX

根据 HQL 规则,这对于指定 javax.persistence.OrderColumn 注解的 Map 和 Lists 都有效,以引用 Map 键或 List 位置(回答 OrderColumn 值)。但是,Java Persistence 查询语言保留在 List 案例中使用,并为 MAP 案例添加 KEY。对 Jakarta Persistence 提供商可移植性感兴趣的应用应了解这一区别。

KEY

仅对映射有效。指地图的密钥。如果密钥本身是一个实体,可以进一步导航。

ENTRY

仅对映射有效。引用 Map 的逻辑 java.util.Map.Entry tuple(其键和值的组合)。ENTRY 仅作为终端路径有效,且仅在 select 子句中有效。

示例:限定集合参考

// Product.images is a Map<String,String> : key = a name, value = file path

// select all the image file paths (the map value) for Product#123
select i
from Product p
    join p.images i
where p.id = 123

// same as above
select value(i)
from Product p
    join p.images i
where p.id = 123

// select all the image names (the map key) for Product#123
select key(i)
from Product p
    join p.images i
where p.id = 123

// select all the image names and file paths (the 'Map.Entry') for Product#123
select entry(i)
from Product p
    join p.images i
where p.id = 123

// total the value of the initial line items for all orders for a customer
select sum( li.amount )
from Customer c
        join c.orders o
        join o.lineItems li
where c.id = 123
  and index(li) = 1

4.6. 关于 HQL 功能

HQL 定义一些可用的标准功能,无论使用的底层数据库是什么。HQL 也可以了解方形图和应用程序中定义的其他功能。

4.6.1. 关于 HQL 标准化功能

无论使用的底层数据库是什么,HQL 中都提供以下功能:

表 4.3. HQL 标准化功能

功能描述

BIT_LENGTH

返回二进制数据的长度。

CAST

执行 SQL 广播.cast 目标应命名为要使用的 Hibernate 映射类型。

EXTRACT

根据日期时间值执行 SQL 提取.提取将返回日期/时间值的一部分,如当年。请参见以下简写表格。

SECOND

用于提取第二个的缩写提取表单。

MINUTE

用于提取分钟的缩写提取表单。

HOUR

用于提取小时的缩写提取表单。

DAY

用于提取日期的缩写提取表单.

用于提取月份的简短提取表单。

用于提取年度的简短提取表单.

STR

转换值作为字符数据的简写形式。

4.6.2. 关于 HQL 非标准化功能

Hibernate 拨号可以注册已知可用于该特定数据库产品的其他功能。它们只有在使用该数据库或拨号时才可用。以数据库可移植性为目标的应用应避免在此类别中使用函数。

应用程序开发人员还可以提供自己的一组功能。这通常代表自定义 SQL 函数或 SQL 片段的别名。此类功能声明通过使用 org.hibernate.cfg.ConfigurationaddSqlFunction 方法进行。

4.6.3. 关于连接操作

HQL 除了支持串联(CONCAT)功能外,还定义了串联运算符。这不是由 Java Persistence 查询语言定义的,因此便携式应用应避免使用它。连接运算符取自 SQL 串联运算符(||)。

示例:连接操作示例

select 'Mr. ' || c.name.first || ' ' || c.name.last
from Customer c
where c.gender = Gender.MALE

4.7. 关于动态注入

特定的表达式类型仅在 select 子句中有效。Hibernate 将此"动态实例化"称为"动态实例化"。Java Persistence 查询语言支持部分功能,并将其称为"结构表达式"。

示例:动态注入示例 - 结构

select new Family( mother, mate, offspr )
from DomesticCat as mother
    join mother.mate as mate
    left join mother.kittens as offspr

因此,我们不在这里处理 Object[],而是将值嵌套在 type-safe java 对象中,该对象将作为查询的结果返回。类引用必须完全限定,并且必须具有匹配的构造器。

此处的类不需要映射。如果确实代表某一实体,则生成的实例将返回为 NEW 状态(非 managed!)。

这也是 Java Persistence 查询语言支持的部分。HQL 支持其他"动态实例化"功能。首先,查询可以指定返回列表,而不是用于 scalar 结果的 Object[]:

示例:动态注入示例 - 列表

select new list(mother, offspr, mate.name)
from DomesticCat as mother
    inner join mother.mate as mate
    left outer join mother.kittens as offspr

这个查询的结果将是 List<List>,而不是 List<Object[]>。

HQL 还支持将井号结果换算成一个映射。

示例:动态注入示例 - 映射

select new map( mother as mother, offspr as offspr, mate as mate )
from DomesticCat as mother
    inner join mother.mate as mate
    left outer join mother.kittens as offspr

select new map( max(c.bodyWeight) as max, min(c.bodyWeight) as min, count(*) as n )
from Cat cxt

这个查询的结果将是 List<Map<String,Object>>,而不是 List<Object[]>。映射的键由提供给所选表达式的别名定义。

4.8. 关于 HQL predicates

predicates 形成 where 子句、包含 子句 搜索案例表达式的基础。它们是可解析为真实值的表达式,通常是 TRUE 或 FALSE,尽管涉及 NULL 值的布尔值比较通常解析为 UNKNOWN

HQL 谓词

  • null Predicate

    检查 null 值。可以应用到基本属性引用、实体引用和参数。HQL 还允许将它应用到组件/嵌入式类型。

    示例:NULL Check

    // select everyone with an associated address
    select p
    from Person p
    where p.address is not null
    
    // select everyone without an associated address
    select p
    from Person p
      where p.address is null

  • 像 Predicate

    执行类似于字符串值的比较。语法为:

    like_expression ::=
           string_expression
           [NOT] LIKE pattern_value
           [ESCAPE escape_character]

    语义遵循 SQL 等表达式的语义。pattern_value 是在 string _expression 中尝试匹配的模式。正如 SQL 一样,mod_value 可以使用 _ (下划线)和 %(百分比 )作为通配符。含义相同。_ 匹配任何单个字符。% 匹配任意数量的字符。

    可选的s cap_character 用于指定用于转义 pattern_value_% 的特殊含义的转义字符。这在需要搜索模式(包括 _ 或 %) 时非常有用。

    示例:LIKE Predicate

    select p
    from Person p
    where p.name like '%Schmidt'
    
    select p
    from Person p
    where p.name not like 'Jingleheimmer%'
    
    // find any with name starting with "sp_"
    select sp
    from StoredProcedureMetadata sp
    where sp.name like 'sp|_%' escape '|'

  • Predicate 间

    类似于 SQL BETWEEN 表达式。执行评估,说明值在 2 个其他值范围内。所有操作对象都应具有可比较类型。

    示例:BETWEEN Predicate

    select p
    from Customer c
        join c.paymentHistory p
    where c.id = 123
      and index(p) between 0 and 9
    
    select c
    from Customer c
    where c.president.dateOfBirth
            between {d '1945-01-01'}
                and {d '1965-01-01'}
    
    select o
    from Order o
    where o.total between 500 and 5000
    
    select p
    from Person p
    where p.name between 'A' and 'E'

  • IN Predicate

    IN predicate 执行检查特定值是否在值列表中。它的语法是:

    in_expression ::= single_valued_expression
                [NOT] IN single_valued_list
    
    single_valued_list ::= constructor_expression |
                (subquery) |
                collection_valued_input_parameter
    
    constructor_expression ::= (expression[, expression]*)

    single_valued_expression 的类型和 single _valued _list 中的单个值 必须一致。Java Persistence 查询语言将此处的有效类型限制为字符串、数字、日期、时间、时间戳和枚举类型。在 Java Persistence 查询语言 中,single_valued_expression 只能 指:

    • "状态字段",这是简单属性的术语。特别是,这不包括关联和组件/嵌入式属性。
    • 实体类型表达式.

      在 HQL 中,single_valued_expression 可以指 一组更广泛的表达式类型。允许单值关联。同样是组件/嵌入式属性,尽管该功能取决于底层数据库中对元或"行值构造器语法"的支持级别。此外,HQL 不会以任何方式限制值类型,但应用开发人员应该意识到,不同的类型可能会基于底层数据库供应商获得有限的支持。这主要是 Java Persistence 查询语言限制的原因。

      值列表可能来自多个不同来源。在 constructor_expressioncollection_valued_input_parameter 中,值列表不能为空;它必须至少包含一个值。

      示例:IN Predicate

      select p
      from Payment p
      where type(p) in (CreditCardPayment, WireTransferPayment)
      
      select c
      from Customer c
      where c.hqAddress.state in ('TX', 'OK', 'LA', 'NM')
      
      select c
      from Customer c
      where c.hqAddress.state in ?
      
      select c
      from Customer c
      where c.hqAddress.state in (
          select dm.state
          from DeliveryMetadata dm
          where dm.salesTax is not null
      )
      
      // Not Java Persistence query language compliant!
      select c
      from Customer c
      where c.name in (
          ('John','Doe'),
          ('Jane','Doe')
      )
      
      // Not Java Persistence query language compliant!
      select c
      from Customer c
      where c.chiefExecutive in (
          select p
          from Person p
          where ...
      )

4.9. 关于关系比较

比较涉及比较运算符之一 - =, >, >=, <, ›, <>。HQL 还定义了 != 作为与 <> 的比较运算符。操作对象应该是相同的类型。

示例:关系比较示例

// numeric comparison
select c
from Customer c
where c.chiefExecutive.age < 30

// string comparison
select c
from Customer c
where c.name = 'Acme'

// datetime comparison
select c
from Customer c
where c.inceptionDate < {d '2000-01-01'}

// enum comparison
select c
from Customer c
where c.chiefExecutive.gender = com.acme.Gender.MALE

// boolean comparison
select c
from Customer c
where c.sendEmail = true

// entity type comparison
select p
from Payment p
where type(p) = WireTransferPayment

// entity value comparison
select c
from Customer c
where c.chiefExecutive = c.chiefTechnologist

比较还可能涉及子队列限定符 - ALL、ANY、SOM ESOMEANY 是同义词。

如果对子队列结果中的所有值进行比较都为 true,则 ALL 限定符会解析为 true。如果子队列结果为空,它将解析为 false。

示例:所有 Subquery Comparison Qualifier 示例

// select all players that scored at least 3 points
// in every game.
select p
from Player p
where 3 > all (
   select spg.points
   from StatsPerGame spg
   where spg.player = p
)

如果对 队列结果中至少一个值进行比较为 true,ANY /SOME 限定符会解析为 true。如果子队列结果为空,它将解析为 false。

4.10. 字节码增强

4.10.1. lazy Attribute Loading

lazy 属性加载是一种字节码增强,它允许您告知 Hibernate,从数据库获取时仅应加载实体的特定部分,以及应在何时加载其他剩余部分。这与基于代理加载的理念不同,后者是实体中心,即在需要时一次性加载实体的状态。通过字节码增强,根据需要加载各个属性或属性组。

可以将 lazy 属性指定为一起加载,这称为 lazy 组。默认情况下,所有单数属性都是单个组的一部分。访问一个 lazy singular 属性时,会加载所有 lazy 单数属性。与单片组不同,lazy 复数属性是各个离散的 lazy 组。此行为可通过 @org.hibernate.annotations.LazyGroup 注释显式控制。

@Entity
public class Customer {

    @Id
    private Integer id;

    private String name;

    @Basic( fetch = FetchType.LAZY )
    private UUID accountsPayableXrefId;

    @Lob
    @Basic( fetch = FetchType.LAZY )
    @LazyGroup( "lobs" )
    private Blob image;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public UUID getAccountsPayableXrefId() {
        return accountsPayableXrefId;
    }

    public void setAccountsPayableXrefId(UUID accountsPayableXrefId) {
        this.accountsPayableXrefId = accountsPayableXrefId;
    }

    public Blob getImage() {
        return image;
    }

    public void setImage(Blob image) {
        this.image = image;
    }
}

在上例中,有两个 lazy 属性:accounts PayableXrefIdimage。这些属性各自属于不同的获取组。accountsPayableXrefId 属性是默认 fetch 组的一部分,这意味着访问 accountsPayableXrefId 不会强制加载 映像 属性,反之亦然。

第 5 章 Hibernate 服务

5.1. 关于 Hibernate 服务

服务是向 Hibernate 提供各种功能的可插拔实现的类。具体来说,它们是某些服务合同接口的实施。接口称为服务角色;实施类称为服务实施。般而言,用户可以插入所有标准服务角色(覆盖)的替代实施;他们还可以定义服务角色基础组之外的其他服务(扩展)。

5.2. 关于服务合同

服务的基本要求是实施标记接口 org.hibernate.service.Service。Hibernate 在内部将此用于某些基本类型安全。

服务也可以实施 org.hibernate.service.spi.Startable 和 org.hibernate.service.spi.Stoppable 接口来接收启动和停止的通知。另一个可选服务合同是 org.hibernate.service.spi.Manageable,在 Jakarta 管理中将服务标记为可管理,但 Jakarta 管理集成已启用。

5.3. 服务依赖项类型

允许服务使用以下方法之一声明对其他服务的依赖:

@org.hibernate.service.spi.InjectService

服务实施类上接受单个参数并标有 @InjectService 的任何方法都被视为请求注入其他服务。

默认情况下,方法参数的类型应当是要注入的服务角色。如果参数类型与 service 角色不同,则应当使用 InjectService 的 serviceRole 属性来显式命名该角色。

默认情况下,注入的服务被视为必需,如果缺少指定的依赖服务,则启动该服务将失败。如果要注入的服务是可选的,InjectService 的 required 属性应声明为 false。默认值为 true

org.hibernate.service.spi.ServiceRegistryAwareService

第二种方法是拉取方法,其中服务实施可选的服务接口 org.hibernate.service.spi.ServiceRegistryAwareService,它声明了单一 注入服务方法

在启动过程中,Hibernate 会将 org.hibernate.service.ServiceRegistry 自身注入到实施此接口的服务中。然后,服务可以使用 ServiceRegistry 引用来查找所需的任何其他服务。

5.3.1. Service Registry

5.3.1.1. 关于 ServiceRegistry

除服务本身外,中央服务 API 是 org.hibernate.service.ServiceRegistry 接口。服务注册表的主要用途是保存、管理和提供对服务的访问。

服务注册表采用层次结构。个注册表中的服务可以依赖于并使用同一注册表中的服务以及任何父注册表。

使用 org.hibernate.service.ServiceRegistryBuilder 构建 org.hibernate.service.ServiceRegistry 实例。

使用 ServiceRegistryBuilder 创建 ServiceRegistry 的示例

ServiceRegistryBuilder registryBuilder =
    new ServiceRegistryBuilder( bootstrapServiceRegistry );
    ServiceRegistry serviceRegistry = registryBuilder.buildServiceRegistry();

5.3.2. 自定义服务

5.3.2.1. 关于自定义服务

旦创建了 org.hibernate.service.ServiceRegistry,则该服务本身可能会接受重新配置,但此处的不可变性意味着添加或替换服务。因此 org.hibernate.service.ServiceRegistryBuilder 提供的另一个角色是允许对从中生成的 org.hibernate.service.ServiceRegistry 中包含的服务进行调整。

有两种方法可以告知 org.hibernate.service.ServiceRegistryBuilder 相关信息。

  • 实施 org.hibernate.service.spi.BasicServiceInitiator 类,以控制服务类按需构建,并使用其 addInitiator 方法将它添加到 org.hibernate.service.ServiceRegistryBuilder 中。
  • 只需实例化服务类,并使用其 addService 方法将它添加到 org.hibernate.service.Service RegistryBuilder 中。

这两种方法都可用于扩展注册表,例如添加新的服务角色和覆盖服务,如替换服务实施。

示例:使用 ServiceRegistryBuilder 将现有服务替换为自定义服务

ServiceRegistryBuilder registryBuilder =
    new ServiceRegistryBuilder(bootstrapServiceRegistry);
registryBuilder.addService(JdbcServices.class, new MyCustomJdbcService());
ServiceRegistry serviceRegistry = registryBuilder.buildServiceRegistry();

public class MyCustomJdbcService implements JdbcServices{

   @Override
   public ConnectionProvider getConnectionProvider() {
       return null;
   }

   @Override
   public Dialect getDialect() {
       return null;
   }

   @Override
   public SqlStatementLogger getSqlStatementLogger() {
       return null;
   }

   @Override
   public SqlExceptionHelper getSqlExceptionHelper() {
       return null;
   }

   @Override
   public ExtractedDatabaseMetaData getExtractedMetaDataSupport() {
       return null;
   }

   @Override
   public LobCreator getLobCreator(LobCreationContext lobCreationContext) {
       return null;
   }

   @Override
   public ResultSetWrapper getResultSetWrapper() {
       return null;
   }
}

5.3.3. Boot-Strap Registry

5.3.3.1. 关于 Boot-strap Registry

boot-strap 注册表存放绝对必须可用的服务,大多数操作都必须可用。这里的主要服务是 ClassLoaderService,这是一个完美的例子。即使解析配置文件也需要访问类加载服务,如资源查找。这是通常使用的根注册表,而不是父注册表。

boot-strap 注册表的实例使用 org.hibernate.service.BootstrapServiceRegistryBuilder 类构建。

Using BootstrapServiceRegistryBuilder

示例:使用 BootstrapServiceRegistryBuilder

BootstrapServiceRegistry bootstrapServiceRegistry =
    new BootstrapServiceRegistryBuilder()
    // pass in org.hibernate.integrator.spi.Integrator instances which are not
    // auto-discovered (for whatever reason) but which should be included
    .with(anExplicitIntegrator)
    // pass in a class loader that Hibernate should use to load application classes
    .with(anExplicitClassLoaderForApplicationClasses)
    // pass in a class loader that Hibernate should use to load resources
    .with(anExplicitClassLoaderForResources)
    // see BootstrapServiceRegistryBuilder for rest of available methods
    ...
    // finally, build the bootstrap registry with all the above options
    .build();

5.3.3.2. BootstrapRegistry 服务

org.hibernate.service.classloading.spi.ClassLoaderService

Hibernate 需要与类加载器交互。但是,Hibernate 或任何库与类加载器交互的方式因托管应用的运行时环境而异。应用程序服务器、OSGi 容器和其他模块化类加载系统带来了非常具体的类加载要求。此服务从这种环境复杂性中提供 Hibernate 抽象。更重要的是,它以单一兼容的方式做到这一点。

在与类加载器交互方面,Hibernate 需要以下功能:

  • 定位应用程序类的功能
  • 定位集成类的功能
  • 查找资源(如属性文件和 XML 文件)的功能
  • 加载 java.util.ServiceLoader 的功能

    注意

    目前,加载应用类的功能和加载集成类的功能组合到服务的单个负载类功能中。这可能在以后的版本中有所改变。

org.hibernate.integrator.spi.IntegratorService

应用程序、附加组件和其他模块需要与 Hibernate 集成。以上方法需要一个组件(通常是应用)来协调各个模块的注册。此注册代表每个模块的集成商进行。

此服务侧重于发现方面。它利用 org.hibernate .service.classloading.spi.ClassLoaderService 提供的标准 Java java.util.ServiceLoader 功能来发现 org.hibernate.integrator.spi.Integrator 合同的实施。

集成器只需定义一个名为 /META-INF/services/org.hibernate.integrator.spi.Integrator 的文件,并使其在类路径中可用。

此文件由 java.util.ServiceLoader 机制使用。它将列出实施 org.hibernate.integrator.spi.Integrator 接口的完全限定类名称,每行一个。

5.3.4. SessionFactory Registry

虽然最佳做法是将所有 registry 类型的实例视为针对给定 机构。SessionFactory,但该组中的服务实例明确属于单个 org.hibernate.SessionFactory

差别在于需要发起它们的时间问题。通常他们需要访问 org.hibernate.SessionFactory 才能启动。这个特殊 registry 是 org.hibernate.service.spi.SessionFactoryServiceRegistry

5.3.4.1. SessionFactory 服务

org.hibernate.event.service.spi.EventListenerRegistry

描述
用于管理事件侦听器的服务。
initiator
org.hibernate.event.service.internal.EventListenerServiceInitiator
实施
org.hibernate.event.service.internal.EventListenerRegistryImpl

5.3.5. 集成器

org.hibernate.integrator.spi.Integrator 旨在提供一种简单的途径,让开发人员能够将信息集中到构建可正常工作的 SessionFactory 的过程中。org.hibernate.integrator.spi.Integrator 接口定义了两种感兴趣的方法:

  • 集成 使我们能够在构建过程中 hook
  • 解除 集成使我们可以固定在 SessionFactory 关机中。
注意

org.hibernate.integrator.spi.Integrator 中定义了第三个方法,它是一个超载的集成形式,接受 org.hibernate.metamodel.source.MetadataImplementor 而不是 org.hibernate.cfg.Configuration

除了 IntegratorService 提供的发现方法外,应用在构建 BootstrapService Registry 时可以手动注册 Integrator 实施。

5.3.5.1. 集成器用例

org.hibernate.integrator.spi.Integrator 注册事件监听程序和提供服务,请参阅 org.hibernate.integrator.spi.ServiceContributingIntegrator

示例:注册事件列表

public class MyIntegrator implements org.hibernate.integrator.spi.Integrator {

    public void integrate(
            Configuration configuration,
            SessionFactoryImplementor sessionFactory,
            SessionFactoryServiceRegistry serviceRegistry) {
        // As you might expect, an EventListenerRegistry is the thing with which event listeners are registered  It is a
        // service so we look it up using the service registry
        final EventListenerRegistry eventListenerRegistry = serviceRegistry.getService(EventListenerRegistry.class);

        // If you wish to have custom determination and handling of "duplicate" listeners, you would have to add an
        // implementation of the org.hibernate.event.service.spi.DuplicationStrategy contract like this
        eventListenerRegistry.addDuplicationStrategy(myDuplicationStrategy);

        // EventListenerRegistry defines 3 ways to register listeners:
        //     1) This form overrides any existing registrations with
        eventListenerRegistry.setListeners(EventType.AUTO_FLUSH, myCompleteSetOfListeners);
        //     2) This form adds the specified listener(s) to the beginning of the listener chain
        eventListenerRegistry.prependListeners(EventType.AUTO_FLUSH, myListenersToBeCalledFirst);
        //     3) This form adds the specified listener(s) to the end of the listener chain
        eventListenerRegistry.appendListeners(EventType.AUTO_FLUSH, myListenersToBeCalledLast);
    }
}

第 6 章 Hibernate Envers

6.1. 关于 Hibernate Envers

Hibernate Envers 是一种审计和版本化系统,为 JBoss EAP 提供了一种途径来跟踪永久类的历史变化。为标有 @Audited 的实体创建审计表,该实体存储对实体所做的更改历史记录。然后可以检索和查询数据。

Envers 允许开发人员:

  • 审计根据 Jakarta Persistence 规范定义的所有映射
  • 审核扩展 Jakarta Persistence 规范的所有 hibernate 映射
  • 由或使用原生 Hibernate API 映射的审计实体
  • 使用修订实体记录每个修订版本的数据
  • 查询历史数据

6.2. 关于审计持久性类

持久类审计通过 Hibernate Envers 和 @Audited 注释在 JBoss EAP 中完成。当注解应用到类时,将创建一个表,用于存储实体的修订历史记录。

每次对类进行更改时,都会向 audit 表中添加一个条目。该条目包含对类的更改,并获得修订号。这意味着可以回滚更改,也可以查看以前的修订版本。

6.3. 审计策略

6.3.1. 关于审计策略

审计策略定义了审计信息的持久性、查询和存储方式。Hibernate Envers 目前有两种审计策略:

默认审计策略
  • 此策略将审计数据与开始修订一起保留。对于在审计表中插入、更新或删除的每一行,在审计表中插入一行或多行,以及其有效期的开始修订。
  • 插入后不会更新审计表中的行。对审计信息查询使用子查询来选择审计表中适用的行,这些行速度慢且难以索引。
有效期审计策略
  • 此策略存储启动修订以及审计信息的结束修订。对于在审计表中插入、更新或删除的每一行,在审计表中插入一行或多行,以及其有效期的开始修订。
  • 同时,上一审计行(如果可用)的结束修订字段被设置为这个修订版本。然后,对审计信息的查询可以在开始和结束修订版本之间使用,而不是子查询。这意味着保留审计信息的速度稍慢,因为增加了更新,但检索审计信息的速度要快得多。
  • 这也可以通过添加额外的索引来改进。

如需有关审计的更多信息,请参阅关于审计持久类。要为应用设置审计策略,请参阅 设置审计策略

6.3.2. 设置审计策略

JBoss EAP 支持两种审计策略:

  • 默认审计策略
  • 有效期审计策略
定义审计策略

在应用的 persistence .xml 文件中配置 org.hibernate.envers. audit_strategy 属性。如果在 persistence.xml 文件中未设置 属性,则使用默认的审计策略。

设置默认审计策略

<property name="org.hibernate.envers.audit_strategy" value="org.hibernate.envers.strategy.DefaultAuditStrategy"/>

设置Validity Audit 策略

<property name="org.hibernate.envers.audit_strategy" value="org.hibernate.envers.strategy.ValidityAuditStrategy"/>

6.3.3. 将审计支持添加到 Jakarta Persistence Entity

流程

JBoss EAP 通过 Hibernate Envers 使用实体审核来跟踪永久类的历史更改。本节介绍添加对 Jakarta Persistence 实体的审计支持。

将审计支持添加到 Jakarta Persistence Entity

  1. 配置可用的审计参数以适合部署。详情请参阅 配置 Envers 参数
  2. 打开 Jakarta Persistence 实体进行审计。
  3. 导入 org.hibernate.envers.Audited 接口。
  4. @Audited 注释应用到要审核的每个字段或属性,或将它应用到整个类。

    示例:审计两个字段

    import org.hibernate.envers.Audited;
    
    import javax.persistence.Entity;
    import javax.persistence.Id;
    import javax.persistence.GeneratedValue;
    import javax.persistence.Column;
    
    @Entity
    public class Person {
        @Id
        @GeneratedValue
        private int id;
    
        @Audited
        private String name;
    
        private String surname;
    
        @ManyToOne
        @Audited
        private Address address;
    
        // add getters, setters, constructors, equals and hashCode here
    }

    示例:审计最终类

    import org.hibernate.envers.Audited;
    
    import javax.persistence.Entity;
    import javax.persistence.Id;
    import javax.persistence.GeneratedValue;
    import javax.persistence.Column;
    
    @Entity
    @Audited
    public class Person {
        @Id
        @GeneratedValue
        private int id;
    
        private String name;
    
        private String surname;
    
        @ManyToOne
        private Address address;
    
        // add getters, setters, constructors, equals and hashCode here
    }

为审核配置了 Jakarta Persistence 实体时,将创建一个名为 _AUD 的表来存储历史更改。

6.4. Configuration

6.4.1. 配置端点参数

JBoss EAP 通过 Hibernate Envers 使用实体审计来跟踪永久类的历史更改。

配置可用的端点参数

  1. 打开 应用的 persistent.xml 文件。
  2. 根据需要添加、删除或配置 Envers 属性。有关可用属性列表,请参阅 Envers Configuration Properties

    示例:结束参数

    <persistence-unit name="mypc">
      <description>Persistence Unit.</description>
      <jta-data-source>java:jboss/datasources/ExampleDS</jta-data-source>
      <shared-cache-mode>ENABLE_SELECTIVE</shared-cache-mode>
      <properties>
        <property name="hibernate.hbm2ddl.auto" value="create-drop" />
        <property name="hibernate.show_sql" value="true" />
        <property name="hibernate.cache.use_second_level_cache" value="true" />
        <property name="hibernate.cache.use_query_cache" value="true" />
        <property name="hibernate.generate_statistics" value="true" />
        <property name="org.hibernate.envers.versionsTableSuffix" value="_V" />
        <property name="org.hibernate.envers.revisionFieldName" value="ver_rev" />
      </properties>
    </persistence-unit>

6.4.2. 在运行时启用或禁用审计

在运行时启用或禁用实体版本审核

  1. 子类 AuditEventListener 类。
  2. 覆盖在 Hibernate 事件中调用的以下方法:

    • onPostInsert
    • onPostUpdate
    • onPostDelete
    • onPreUpdateCollection
    • onPreRemoveCollection
    • onPostRecreateCollection
  3. 将子类指定为事件的监听程序。
  4. 确定是否应审计更改。
  5. 如果更改应该被审计,则将调用传递到超级类。

6.4.3. 配置条件审计

Hibernate Envers 使用一系列事件监听器以对各种 Hibernate 事件的响应保留审计数据。如果 Envers JAR 在类路径中,则这些监听程序会自动注册。

实施条件审计

  1. persistence .xml 文件中将 hibernate.listeners.envers. autoRegister Hibernate 属性设置为 false。
  2. 子类要覆盖的每个事件监听程序。将条件审计逻辑放在子类中,并在应当执行审计时调用超级方法。
  3. 创建 org.hibernate.integrator.spi.Integrator 的自定义实施,类似于 org.hibernate.envers.event.EnversIntegrator。使用在第 2 步中创建的事件监听器子类,而不是默认的类。
  4. META-INF/services/org.hibernate.integrator.spi.Integrator 文件添加到 JAR。此文件应当包含实施接口的类的完全限定名称。

6.4.4. Envers 配置属性

表 6.1. 实体数据版本配置参数

属性名称默认值描述

org.hibernate.envers.audit_table_prefix

 

在被审计实体名称前加上字符串,以创建保存审计信息的实体的名称。

org.hibernate.envers.audit_table_suffix

_AUD

附加到已审计实体名称的字符串,以创建保存审计信息的实体的名称。例如,如果对表名称为 Person 的实体进行了审计,Envers 将生成名为 Person_AUD 的表来存储历史数据。

org.hibernate.envers.revision_field_name

REV

包含修订号的审计实体中的字段名称。

org.hibernate.envers.revision_type_field_name

REVTYPE

存放修订类型的审计实体中的字段名称。当前可能的修订类型有: 添加、修改 传送 以分别插入、修改或删除。

org.hibernate.envers.revision_on_collection_change

true

此属性决定是否应生成修订项,如果关系字段未拥有的更改。这可以是一对多关系中的集合,也可以是使用一对一关系中的 mapping By 属性的字段。

org.hibernate.envers.do_not_audit_optimistic_locking_field

true

为 true 时,用于开放式锁定的属性(使用 @Version标注)将自动从审计中排除。

org.hibernate.envers.store_data_at_delete

false

此属性定义在删除实体时是否应将实体数据存储在修订中,所有其他属性均标记为 null(而非 ID)。这通常不需要,因为数据存在于最后一处的修订版本中。但有时候,在最后一个修订版本中访问它更为简单和高效。但是,这意味着在删除前包含的数据被存储两次。

org.hibernate.envers.default_schema

Null(与普通表相同)

用于审计表的默认架构名称。可以使用 @AuditTable(schema="…​") 注释覆盖。如果不存在,则架构将与普通表的架构相同。

org.hibernate.envers.default_catalog

Null(与普通表相同)

应用于审计表的默认目录名称。可以使用 @AuditTable(catalog="…​") 注释覆盖。如果没有,目录将与普通表的目录相同。

org.hibernate.envers.audit_strategy

org.hibernate.envers.strategy.DefaultAuditStrategy

此属性定义在持久保留审计数据时应使用的审计策略。默认情况下,仅存储了实体修改的修订版本。另外,org.hibernate.envers.strategy.ValidityAuditStrategy 存储 start 修订版本和结尾修订版本。它们一起定义审计行何时有效。

org.hibernate.envers.audit_strategy_validity_end_rev_field_name

REVEND

在审计实体中保存最终修订版本的列名称。只有使用了有效期审计策略时,此属性才有效。

org.hibernate.envers.audit_strategy_validity_store_revend_timestamp

false

此属性定义除结束修订本身外,是否应将最终修订的时间戳(数据在最后有效的位置)存储下来。这对于使用表分区从关系数据库中清除旧的审计记录非常有用。分区需要表中存在的列。只有在使用了Validity AuditStrategy 时才会评估此属性。

org.hibernate.envers.audit_strategy_validity_revend_timestamp_field_name

REVEND_TSTMP

结束修订版本时间戳的列名称,即数据仍有效。只有在使用了Validity AuditStrategy 时才使用,org.hibernate.envers.audit_strategy_validity_store_revend_timestamp 评估为 true。

6.5. 查询审计信息

6.5.1. 通过队列检索审计信息

Hibernate Envers 提供通过查询检索审计信息的功能。

注意

许多情况下,对审计数据的查询比 实时数据 的相应查询要慢得多,因为它们涉及关联的子选择。

通过给定修订版本查询类实体

此查询的入口点为:

AuditQuery query = getAuditReader()
    .createQuery()
    .forEntitiesAtRevision(MyEntity.class, revisionNumber);

然后,可以使用 AuditEntity 工厂类别指定限制。以下查询仅选择 name 属性等于 John 的实体:

query.add(AuditEntity.property("name").eq("John"));

以下查询只选择与给定实体相关的实体:

query.add(AuditEntity.property("address").eq(relatedEntityInstance));
// or
query.add(AuditEntity.relatedId("address").eq(relatedEntityId));

然后可以订购、限制结果,并且设置聚合和预测(分组除外)。以下示例是一个完整的查询。

List personsAtAddress = getAuditReader().createQuery()
    .forEntitiesAtRevision(Person.class, 12)
    .addOrder(AuditEntity.property("surname").desc())
    .add(AuditEntity.relatedId("address").eq(addressId))
    .setFirstResult(4)
    .setMaxResults(2)
    .getResultList();

查询修订,其中给定类的实体更改

此查询的入口点为:

AuditQuery query = getAuditReader().createQuery()
    .forRevisionsOfEntity(MyEntity.class, false, true);

限制可以添加到此查询中,方式与上例相同。这个查询还有其它可能:

AuditEntity.revisionNumber()
指定修改审计实体的修订版本号的限制、预测和顺序。
AuditEntity.revisionProperty(propertyName)
指定修订实体属性的限制、预测和订单,对应于修改审计实体的修订版本。
AuditEntity.revisionType()
提供对修订版本类型的访问(ADD、MOD、DEL)。

然后可以根据需要调整查询结果。以下查询选择 MyEntity 类的实体的最小修订号,其中的 entity Id ID 在修订号 42 后更改:

Number revision = (Number) getAuditReader().createQuery()
    .forRevisionsOfEntity(MyEntity.class, false, true)
    .setProjection(AuditEntity.revisionNumber().min())
    .add(AuditEntity.id().eq(entityId))
    .add(AuditEntity.revisionNumber().gt(42))
    .getSingleResult();

对修订的查询也可以最小化/最大化属性。以下查询选择给定实体的 actualDate 值大于给定值的修订版本,但尽量小:

Number revision = (Number) getAuditReader().createQuery()
    .forRevisionsOfEntity(MyEntity.class, false, true)
    // We are only interested in the first revision
    .setProjection(AuditEntity.revisionNumber().min())
    .add(AuditEntity.property("actualDate").minimize()
        .add(AuditEntity.property("actualDate").ge(givenDate))
        .add(AuditEntity.id().eq(givenEntityId)))
    .getSingleResult();

mini ()和 max()方法 返回一个条件,可以向其中添加约束,但具有最大/最小 属性的实体必须满足此条件。

创建查询时传递两个布尔值参数:

selectEntitiesOnly

这个参数只有在未设置显式投射时才有效。
如果为 true,则查询的结果将是满足指定限制修订版本时更改的实体列表。
为 false,则结果将是三个元素数组的列表。第一个元素是更改后的实体实例。第二个是包含修订数据的实体。如果不使用自定义实体,这将是 DefaultRevisionEntity 实例。第三个元素数组将是修订的类型(ADD、MOD、DEL)。
selectDeletedEntities
此参数指定是否必须将删除实体的修订包含在结果中。如果为 true,实体将具有修订类型 DEL,除 id 外的所有字段都将值为 null

查询修改后属性的实体的修订

以下查询将返回 MyEntity 及给定 ID 的所有修订,其中的 actualDate 属性已更改。

AuditQuery query = getAuditReader().createQuery()
  .forRevisionsOfEntity(MyEntity.class, false, true)
  .add(AuditEntity.id().eq(id));
  .add(AuditEntity.property("actualDate").hasChanged())

hasChanged 条件可以和附加标准组合。以下查询将在生成 revisionNumber 时为 MyEntity 返回一个横向片段。它仅限于修改 prop1 但不修改 prop 2 的修订版本。

AuditQuery query = getAuditReader().createQuery()
  .forEntitiesAtRevision(MyEntity.class, revisionNumber)
  .add(AuditEntity.property("prop1").hasChanged())
  .add(AuditEntity.property("prop2").hasNotChanged());

结果集还包含数字低于 revisionNumber 的修订版本。这意味着,这个查询无法读取为"通过 prop1 修改和 prop 2 不更改的 revisionNumber 中所有 MyEntities 更改"。

以下查询显示如何使用 forEntitiesModifiedAtRevision 查询返回这个结果:

AuditQuery query = getAuditReader().createQuery()
  .forEntitiesModifiedAtRevision(MyEntity.class, revisionNumber)
  .add(AuditEntity.property("prop1").hasChanged())
  .add(AuditEntity.property("prop2").hasNotChanged());

在给定修订版本中修改查询实体

以下示例显示了给定修订中修改的实体的基本查询。它允许检索指定修订中更改的实体名称和对应 Java 类:

Set<Pair<String, Class>> modifiedEntityTypes = getAuditReader()
    .getCrossTypeRevisionChangesReader().findEntityTypes(revisionNumber);

还可以从 org.hibernate.envers.CrossTypeRevisionChangesReader 访问许多其他查询:

list<Object> findEntities(Number)
返回给定修订中更改(添加、更新和删除)的所有审计实体的快照。执行 n+1 SQL 查询,其中 n 是指定修订版本中修改的多个不同实体类。
List<Object> findEntities(Number, RevisionType)
返回给定修订版本中更改(添加、更新或删除)的所有审计实体的快照,并按照修改类型过滤。执行 n+1 SQL 查询,其中 n 是指定修订版本中修改的多个不同实体类。Map<RevisionType, List<Object>>
findEntitiesGroupByRevisionType(Number)
返回包含由修改操作分组的实体快照列表的映射,如添加、更新或删除。执行 3n+1 SQL 查询,其中 n 是指定修订版本中修改的多个不同实体类。

6.5.2. 使用参考实体属性的遍历实体协会

您可以使用引用实体的属性来遍历查询中的实体。这可让您查询一对一和多对一关联。

以下示例演示了您可以在查询中遍历实体的一些方式。

  • 在修订号 1 中,查找所有者年龄为 20 岁或住在地址号 30 的车子,然后按照汽车制作排列结果。

    List<Car> resultList = auditReader.createQuery()
                    .forEntitiesAtRevision( Car.class, 1 )
                    .traverseRelation( "owner", JoinType.INNER, "p" )
                    .traverseRelation( "address", JoinType.INNER, "a" )
                    .up().up().add( AuditEntity.disjunction().add(AuditEntity.property( "p", "age" )
                           .eq( 20 ) ).add( AuditEntity.property( "a", "number" ).eq( 30 ) ) )
                    .addOrder( AuditEntity.property( "make" ).asc() ).getResultList();
  • 在修订号 1 中,查找所有者期限等于所有者地址号的车辆。

    Car result = (Car) auditReader.createQuery()
                    .forEntitiesAtRevision( Car.class, 1 )
                    .traverseRelation( "owner", JoinType.INNER, "p" )
                    .traverseRelation( "address", JoinType.INNER, "a" )
                    .up().up().add(AuditEntity.property( "p", "age" )
                            .eqProperty( "a", "number" ) ).getSingleResult();
  • 在修订号 1 中,查找所有者为 20 岁或没有所有者的所有车辆。

    List<Car> resultList = auditReader.createQuery()
                    .forEntitiesAtRevision( Car.class, 1 )
                    .traverseRelation( "owner", JoinType.LEFT, "p" )
                    .up().add( AuditEntity.or( AuditEntity.property( "p", "age").eq( 20 ),
                            AuditEntity.relatedId( "owner" ).eq( null ) ) )
                    .addOrder( AuditEntity.property( "make" ).asc() ).getResultList();
  • 在修订号 1 中,找到 make 等于"car3"且所有者年龄为 30 或没有所有者的所有车辆。

    List<Car> resultList = auditReader.createQuery()
                    .forEntitiesAtRevision( Car.class, 1 )
                    .traverseRelation( "owner", JoinType.LEFT, "p" )
                    .up().add( AuditEntity.and( AuditEntity.property( "make" ).eq( "car3" ), AuditEntity.property( "p", "age" ).eq( 30 ) ) )
                    .getResultList();
  • 在修订号 1 中,查找 make 等于"car3"或所有者为 10 或没有所有者的所有车。

    List<Car> resultList = auditReader.createQuery()
                    .forEntitiesAtRevision( Car.class, 1 )
                    .traverseRelation( "owner", JoinType.LEFT, "p" )
                    .up().add( AuditEntity.or( AuditEntity.property( "make" ).eq( "car3" ), AuditEntity.property( "p", "age" ).eq( 10 ) ) )
                    .getResultList();

6.6. 性能调优

6.6.1. 备用批处理算法

Hibernate 允许您使用以下四种获取策略之一为关联加载数据: join、Select、subselect 和 batch。在这四种策略中,批处理加载允许最大的性能提升,因为它是选择获取的优化策略。在此策略中,Hibernate 通过指定主或外键列表,在单个 SELECT 语句中检索一组实体实例或集合。批处理获取是对 lazy 选择获取策略的优化。

有两种方法可以配置批处理获取:每个类级别或每收集级别。

  • 按类级别

    当 Hibernate 在每个类级别上加载数据时,它需要批量大小的关联,以便在查询时预加载。例如,请考虑在运行时您有 30 个加载到会话中的 car 对象实例。每个 car 对象属于一个 所有者 对象。如果您要迭代所有 汽车 对象并请求其所有者,通过加载 lazy,Hibernate 将发出 30 个选择声明 - 每个所有者一个。这是性能瓶颈。

    您可以在通过查询请求之前,告诉 Hibernate 预加载下一批所有者的数据。查询了 所有者 对象后,Hibernate 将在同一个 SELECT 语句中查询更多这些对象。

    提前要查询 的所有者 对象数量取决于配置时指定的 batch-size 参数:

    <class name="owner" batch-size="10"></class>

    这会让 Hibernate 查询至少 10 个 所有者 对象,预计在不久的将来会需要它们。当用户查询 A 车 的所有者 时,汽车 B 的所有者 可能已经作为批处理加载的一部分加载。当用户实际需要 car B 的所有者,而不是前往数据库(并发出 SELECT 语句)时,可以从当前会话检索该值。

    除了 batch-size 参数外,Hibernate 4.2.0 还引进了新的配置项,以提高批处理加载性能。配置项称为 Batch Fetch Style 配置,由 hibernate.batch_fetch_style 参数指定。

    支持三种不同的批处理获取方式:inrigacY、PADDED 和 DYNAMIC。要指定要使用的样式,请使用 org.hibernate.cfg.AvailableSettings#BATCH_FETCH_STYLE

    • 强制要求:在旧式加载中,使用一组基于 ArrayHelper.getBatchSizes(int) 预先构建的批处理大小。使用现有可批处理标识符数的下一个小型预构建批处理大小来加载批处理。

      继续前面的示例,批处理大小设置为 30,预先构建的批处理大小为 [30、15、10、9、8、7、. 1]。尝试批量加载 29 个标识符将导致批处理 15、10 和 4。将会有 3 个对应的 SQL 查询,每个查询都从数据库中加载 15、10 和 4 所有者。

    • PADDED - 添加类似于udACY 批处理加载样式。它仍然使用预先构建的批处理大小,但使用下一个bigger 批处理大小,并固定额外的标识符占位符。

      与上例所示,如果初始化 30 个所有者对象,则仅对数据库执行一项查询。

      但是,如果要初始化 29 个所有者对象,Hibernate 仍将仅执行一个批处理大小为 30 的 SQL 选择声明,使用带有重复标识符添加的额外空间 padded。

    • 动态 - 虽然符合批处理大小限制,但这种批处理加载的方式使用要加载的实际对象数量动态构建其 SQL SELECT 语句。

      例如,对于 30 所有者对象,最大批处理大小为 30,检索 30 所有者对象的调用将产生一个 SQL SELECT 语句。调用来检索 35 将产生两个分别批处理大小为 30 和 5 的 SQL 语句。Hibernate 将动态更改第二个 SQL 语句,使其保持为 5(所需数量),同时仍保持为批处理大小限制为 30。这与 PADDED 版本不同,因为第二个 SQL 不会获得 PADDED,与 criACY 样式不同,第二个 SQL 语句没有固定大小 - 第二个 SQL 是动态创建的。

      对于少于 30 个标识符的查询,这种样式只会动态加载请求的标识符数。

  • 按收集级别

    Hibernate 还可以按照上述每个类部分中列出的批处理获取大小和样式进行批处理加载集合。

    要反转上一节中使用的示例,请考虑您需要加载每个 所有者 对象拥有的所有 对象。如果在当前会话迭代过程中加载 10 个 所有者 对象,则迭代所有所有者将生成 10 个 SELECT 语句,每个调用 getCars() 方法一个。如果在 Owner 映射中为行车集合启用批量获取,Hibernate 可以预先获取这些集合,如下所示:

    <class name="Owner"><set name="cars" batch-size="5"></set></class>

    因此,由于批量大小为 5 个,并且使用传统的批处理样式来加载 10 个集合,Hibernate 将执行两个 SELECT 语句,各自检索五个集合。

6.6.2. 不可更改数据的第二级对象缓存

Hibernate 自动在内存中缓存数据以提高性能。这通过内存中缓存实现,该缓存可减少数据库查找的次数,特别是很少更改的数据。

Hibernate 维护两种类型的缓存:主缓存(也称为一级缓存)是必需的。此缓存与当前会话关联,并且所有请求都必须通过它。辅助缓存也称为第二级缓存,是可选的,仅在查询了主缓存后才会使用。

通过先将数据存储到一个状态数组中,数据存储在二级缓存中。这个数组会被深度复制,并将深度副本放入缓存中。相反,可以从缓存读取。这非常适合改变(可传递数据)的数据,但对不可变数据效率较低。

从内存使用情况和处理速度来看,深度复制数据是一项代价昂贵的操作。对于大型数据集,内存和处理速度成为了性能限制因素。Hibernate 允许您指定引用而非复制的不可变数据。Hibernate 现在可以将对数据的引用存储在缓存中,而不是复制整个数据集。

这可以通过将配置设置 hibernate.cache.use_reference_entries 的值更改为 true 来完成。默认情况下,hibernate.cache.use_reference_entries 设置为 false

hibernate.cache.use_reference_entries 设置为 true 时,没有任何关联的不可变数据对象不会复制到二级缓存中,并且仅存储对其的引用。

警告

hibernate.cache.use_reference_entries 设为 true 时,具有关联的不可变数据对象仍会深入复制到二级缓存中。

附录 A. 参考资料

A.1. Hibernate 属性

表 A.1. 在 persistence.xml 文件中配置的连接属性

属性名称描述

javax.persistence.jdbc.driver

org.hsqldb.jdbcDriver

要使用的 JDBC 驱动程序的类名称。

javax.persistence.jdbc.user

SA

用户名。

javax.persistence.jdbc.password

 

密码.

javax.persistence.jdbc.url

jdbc:hsqldb:.

JDBC 连接 URL.

表 A.2. Hibernate 配置属性

属性名称描述

hibernate.dialect

Hibernate org.hibernate.dialect.Dialect.Dialect 的类名称。允许 Hibernate 生成针对特定关系数据库优化的 SQL。

在大多数情况下,Hibernate 将能够根据 JDBC 驱动程序返回的 JDBC 元数据,选择正确的 org.hibernate.dialect.Dialect 实施。

hibernate.show_sql

布尔值.将所有 SQL 语句写入控制台。这是将日志类别 org.hibernate.SQL 设置为 debug 的替代选择。

hibernate.format_sql

布尔值.在日志和控制台中仔细打印 SQL。

hibernate.default_schema

使用生成的 SQL 中给定的 schema/tablespace 限定非限定表名称。

hibernate.default_catalog

使用生成的 SQL 中的给定目录限定非限定表名称。

hibernate.session_factory_name

org.hibernate.SessionFactory 将在创建后在 Java Naming 和 Directory 界面中自动绑定到此名称。例如: jndi/composite/name.Jpa

hibernate.max_fetch_depth

为单点关联(一对一,多对一)设置外部连接获取树的最大深度。0 可禁用默认外部连接获取。建议的值介于 0 到 3 之间。

hibernate.default_batch_fetch_size

设置用于 Hibernate 批处理获取关联的默认大小。建议的值为 4816

hibernate.default_entity_mode

为从此 SessionFactory 中打开的所有会话设置实体表示的默认模式。值包括: dynamic-mapdom4jpojo

hibernate.order_updates

布尔值.强制 Hibernate 按照正在更新的项目的主键值对 SQL 更新进行排序。这将导致高度并发系统中的事务死锁减少。

hibernate.generate_statistics

布尔值.如果启用,Hibernate 将收集对性能调优有用的统计信息。

hibernate.use_identifier_rollback

布尔值.如果启用,则在删除对象时,生成的标识符属性将重置为默认值。

hibernate.use_sql_comments

布尔值.如果启用,Hibernate 将在 SQL 中生成注释,以便于调试。默认值为 false

hibernate.id.new_generator_mappings

布尔值.此属性在使用 @GeneratedValue 时相关。它指示新的 IdentifierGenerator 实施是否用于 javax.persistence.GenerationType.AUTO、javax.persistence.GenerationType.TABLE 和 javax.persistence.GenerationType.SEQUENCE.默认值为 true

hibernate.ejb.naming_strategy

使用 Hibernate EntityManager 时,选择 org.hibernate.cfg.NamingStrategy 实施。Hibernate.ejb.naming_strategy 在 Hibernate 5.0 中不再受支持。如果使用,则会记录一个弃用信息,表示它不再被支持,并已被删除,而是使用 split ImplicitNamingStrategy 和 PhysicalNamingStrategy。

如果应用程序不使用 EntityManager,请按照这里的说明配置 NamingStrategy: Hibernate Reference 文档 - Naming Strategies

有关使用 MetadataBuilder 原生 bootstrapping 并应用隐式命名策略的示例,请参阅 Hibernate 5.0 文档中的 http://docs.jboss.org/hibernate/orm/5.0/userguide/html_single/Hibernate_User_Guide.html#bootstrap-native-metadata。物理命名策略可使用 MetadataBuilder.applyPhysicalNamingStrategy() 应用。有关 org.hibernate.boot.MetadataBuilder 的详情请参考 https://docs.jboss.org/hibernate/orm/5.0/javadocs/

hibernate.implicit_naming_strategy

指定要使用的 org.hibernate.boot.model.naming.ImplicitNamingStrategy 类。Hibernate.implicit_naming_strategy 还可用于配置实现 ImplicitNamingStrategy 的自定义类。为这个设置定义了以下短名称:

  • default - ImplicitNamingStrategyJpaCompliantImpl
  • jpa - ImplicitNamingStrategyJpaCompliantImpl
  • legacy-jpa - ImplicitNamingStrategyLegacyJpaImpl
  • legacy-hbm - ImplicitNamingStrategyLegacyHbmImpl
  • component-path - ImplicitNamingStrategyComponentPathImpl

默认设置由 ImplicitNamingStrategy 在 默认 短名称中定义。如果默认设置为空,则回退将使用 ImplicitNamingStrategyJpaCompliantImpl

hibernate.physical_naming_strategy

可插拔策略合同,用于为数据库对象名称应用物理命名规则。指定要使用的 PhysicalNamingStrategy 类。PhysicalNamingStrategyStandardImpl 默认会被使用。Hibernate.physical_naming_strategy 还可用于配置实现 PhysicalNamingStrategy 的自定义类。

重要

对于 hibernate.id.new_generator_mappings,新应用程序应保留默认值 true。使用 Hibernate 3.3.x 的现有应用可能需要将其更改为 false,以继续使用基于序列对象或表的生成器,并且保持向后兼容性。

表 A.3. Hibernate JDBC 和连接属性

属性名称描述

hibernate.jdbc.fetch_size

决定 JDBC 获取大小的非零值(calls Statement.setFetchSize())

hibernate.jdbc.batch_size

非零值可启用 Hibernate 使用 JDBC2 批处理更新。建议的值介于 5 到 30 之间。

hibernate.jdbc.batch_versioned_data

布尔值.如果 JDBC 驱动程序返回来自 executeBatch() 的正确行数,则将此属性设为 true。然后,Hibernate 将批处理 DML 用于自动版本化的数据。默认值为 false

hibernate.jdbc.factory_class

选择自定义 org.hibernate.jdbc.Batcher。大多数应用都不需要此配置属性。

hibernate.jdbc.use_scrollable_resultset

布尔值.启用通过 Hibernate 使用 JDBC2 可滚动结果集。只有使用用户提供的 JDBC 连接时才需要此属性。Hibernate 使用连接元数据,否则,Hibernate 将使用连接元数据。

hibernate.jdbc.use_streams_for_binary

布尔值.这是一个系统级属性。在将 二进制 或可 序列化 类型写入/从 JDBC 写入/读取时,请使用流。

hibernate.jdbc.use_get_generated_keys

布尔值.启用 JDBC3 Prepared Statement.getGeneratedKeys() 在插入后检索原生生成的密钥。需要 JDBC3+ 驱动程序和 JRE1.4+。如果 JDBC 驱动程序与 Hibernate 标识符生成器有问题,则设置为 false。默认情况下,它会尝试使用连接元数据确定驱动程序功能。

hibernate.connection.provider_class

自定义 org.hibernate.connection.ConnectionProvider 的类名称,它为 Hibernate 提供 JDBC 连接。

hibernate.connection.isolation

设置 JDBC 事务隔离级别。检查 java.sql.Connection 以获得有意义的值,但请注意,大多数数据库不支持所有隔离级别,另一些则定义了额外的非标准隔离。标准值为 1、2、4、8

hibernate.connection.autocommit

布尔值.不建议使用此属性。为 JDBC 池连接启用自动提交。

hibernate.connection.release_mode

指定 Hibernate 应何时释放 JDBC 连接。默认情况下,保留 JDBC 连接,直到会话被显式关闭或断开连接。默认值为 auto,为 Jakarta Transactions 和 CMT 事务策略选择 after_statement,为 JDBC 事务策略选择 after_transaction

可用值为 auto (默认)、on_close、fin _transaction、freject_statement

此设置仅影响 SessionFactory.openSession 返回的会话。对于通过 SessionFactory.getCurrentSession 获取的会话,为控制该会话的连接发行模式而被配置为 CurrentSessionContext 实施。

hibernate.connection.<propertyName>

将 JDBC 属性 <propertyName> 传递给 DriverManager.getConnection( )。

hibernate.jndi.<propertyName>

将属性 <propertyName> 传递给 Java 命名和目录接口 InitialContextFactory

表 A.4. Hibernate 缓存属性

属性名称描述

hibernate.cache.region.factory_class

自定义 CacheProvider 的类名称。

hibernate.cache.use_minimal_puts

布尔值.优化企业级缓存操作,以最小化写入,代价是更频繁的读取。此设置对群集缓存最有用,在 Hibernate3 中,群集缓存实施默认启用此设置。

hibernate.cache.use_query_cache

布尔值.启用查询缓存。单个查询仍然需要设置可缓存。

hibernate.cache.use_second_level_cache

布尔值.用于完全禁用第二级缓存,默认为指定 <cache> 映射的类启用。

hibernate.cache.query_cache_factory

自定义 QueryCache 接口的类名称。默认值为内置的 StandardQueryCache

hibernate.cache.region_prefix

用于第二级缓存区域名称的前缀。

hibernate.cache.use_structured_entries

布尔值.强制 Hibernate 以更易人性的格式将数据存储在第二级缓存中。

hibernate.cache.default_cache_concurrency_strategy

使用 @Cacheable 或 @Cache 时用于指定默认 org.hibernate.annotations.CacheConcurrencyStrategy 的名称的设置。@cache(strategy="..") 用于覆盖此默认值。

表 A.5. Hibernate 事务属性

属性名称描述

hibernate.transaction.factory_class

与 Hibernate 事务 API 一起使用的事务Factory 的类名称。默认为 JDBCTransactionFactory

jta.UserTransaction

JTATransactionFactory 使用的 Java 命名和目录接口名称,从应用服务器获取 Jakarta Transactions UserTransaction

hibernate.transaction.manager_lookup_class

TransactionManagerLookup 的类名称。启用 JVM 级别缓存或在 Jakarta Transactions 环境中使用 hilo 生成器时,需要此设置。

hibernate.transaction.flush_before_completion

布尔值.如果启用,会话将在交易完成前自动清空。内置和自动会话上下文管理是首选的。

hibernate.transaction.auto_close_session

布尔值.如果启用,会话将在交易完成后自动关闭。内置和自动会话上下文管理是首选的。

表 A.6. 其他 Hibernate 属性

属性名称描述

hibernate.current_session_context_class

为"当前" 会话 的范围提供一个自定义策略。值包括 jtathreadmanagedcustom.Class

hibernate.query.factory_class

选择 HQL 解析器实施: org.hibernate.hql.internal.ast.ASTranslatorFactory 或 org.hibernate.hql.internal.classic.ClassicQueryTranslatorFactory

hibernate.query.substitutions

用于从 Hibernate 查询中的令牌映射到 SQL 令牌(令牌可以是功能或字面名称)。例如,hqlLiteral=SQL_LITERAL、hqlFunction=SQLFUNC

hibernate.query.conventional_java_constants

指明 Java 常量是否遵循 Java 命名约定。默认为 false。只有在应用中使用了传统的 Java 常量时,现有应用才可以将其设置为 true

将此设置为 true 可显著提高性能,因为 Hibernate 可以仅通过检查别名是否遵循 Java 命名约定来确定别名是否应该被视为 Java 常态。

当此属性设为 false 时,Hibernate 确定别名应通过尝试将别名加载为类来被视为 Java 常数,这是应用的开销。如果别名无法作为类加载,则 Hibernate 将别名视为 Java 常态。

hibernate.hbm2ddl.auto

创建 SessionFactory 时,自动验证或导出架构 DDL 到数据库。使用 create-drop 时,当 SessionFactory 明确关闭时,数据库架构将被丢弃。属性值选项为 验证更新创建create-drop

hibernate.hbm2ddl.import_files

可选文件的逗号分隔名称,其中包含在 SessionFactory 创建期间执行的 SQL DML 语句。这对于测试或演示非常有用。例如,通过添加 INSERT 语句,可以在部署时使用一组最小的数据进行填充。示例值为 /corps.sql、/dogs.sql

文件顺序很重要,因为执行给定文件的语句后再执行下列文件的声明:这些语句仅在创建架构时才执行,例如将 hibernate.hbm2ddl.auto 设置为 createcreate-drop

hibernate.hbm2ddl.import_files_sql_extractor

自定义 ImportSqlCommandExtractor 的类名称。默认为内置 SingleLineSqlCommandExtractor。这可用于实施一个从每个导入文件提取单个 SQL 语句的专用解析器。Hibernate 还提供 MultipleLinesSqlCommandExtractor,它支持拆分于多行(每个语句末尾的强制分号)的指令/注释和带引号的字符串。

hibernate.bytecode.use_reflection_optimizer

布尔值.这是一个系统级属性,无法在 hibernate.cfg.xml 文件中设置。允许使用字节代码操作,而不是运行时反应。说明性有时在故障排除时很有用。Hibernate 始终需要 cglib 或 javassist,即使优化器已关闭。

hibernate.bytecode.provider

javasist 或 cglib 都可以用作字节操作引擎。默认值为 javassist。该值可以是 javassistcglib

表 A.7. Hibernate SQL Dialects(hibernate.dialect)

RDBMSdialect

DB2

org.hibernate.dialect.DB2Dialect

DB2 AS/400

org.hibernate.dialect.DB2400Dialect

DB2 OS390

org.hibernate.dialect.DB2390Dialect

Firebird

org.hibernate.dialect.FirebirdDialect

FrontBase

org.hibernate.dialect.FrontbaseDialect

H2 数据库

org.hibernate.dialect.H2Dialect

HypersonicSQL

org.hibernate.dialect.HSQLDialect

Informix

org.hibernate.dialect.InformixDialect

Ingres

org.hibernate.dialect.IngresDialect

InterBase

org.hibernate.dialect.InterbaseDialect

MariaDB 10

org.hibernate.dialect.MariaDB10Dialect

MariaDB Galera Cluster 10

org.hibernate.dialect.MariaDB10Dialect

Mckoi SQL

org.hibernate.dialect.MckoiDialect

Microsoft SQL Server 2000

org.hibernate.dialect.SQLServerDialect

Microsoft SQL Server 2005

org.hibernate.dialect.SQLServer2005Dialect

Microsoft SQL Server 2008

org.hibernate.dialect.SQLServer2008Dialect

Microsoft SQL Server 2012

org.hibernate.dialect.SQLServer2012Dialect

Microsoft SQL Server 2014

org.hibernate.dialect.SQLServer2012Dialect

Microsoft SQL Server 2016

org.hibernate.dialect.SQLServer2012Dialect

MySQL5

org.hibernate.dialect.MySQL5Dialect

MySQL5.5

org.hibernate.dialect.MySQL55Dialect

MySQL5.7

org.hibernate.dialect.MySQL57Dialect

Oracle(任何版本)

org.hibernate.dialect.OracleDialect

Oracle 9i

org.hibernate.dialect.Oracle9iDialect

Oracle 10g

org.hibernate.dialect.Oracle10gDialect

Oracle 11g

org.hibernate.dialect.Oracle10gDialect

Oracle 12c

org.hibernate.dialect.Oracle12cDialect

Pointbase

org.hibernate.dialect.PointbaseDialect

PostgreSQL

org.hibernate.dialect.PostgreSQLDialect

PostgreSQL 9.2

org.hibernate.dialect.PostgreSQL9Dialect

PostgreSQL 9.3

org.hibernate.dialect.PostgreSQL9Dialect

PostgreSQL 9.4

org.hibernate.dialect.PostgreSQL94Dialect

Postgres Plus Advanced Server

org.hibernate.dialect.PostgresPlusDialect

progress

org.hibernate.dialect.ProgressDialect

SAP DB

org.hibernate.dialect.SAPDBDialect

Sybase

org.hibernate.dialect.SybaseASE15Dialect

Sybase 15.7

org.hibernate.dialect.SybaseASE157Dialect

Sybase 16

org.hibernate.dialect.SybaseASE157Dialect

Sybase 任意位置

org.hibernate.dialect.SybaseAnywhereDialect

重要

hibernate.dialect 属性应设置为应用数据库的正确 org.hibernate.dialect.Dialect.Dialect 子类。如果指定了点数,Hibernate 将会对某些其他属性使用明智的默认值。这意味着不需要手动指定它们。





修订了 2022 年 2 月 18:22:39 +1000