简介
在本文中,我将解释什么是Hibernate SQM或语义查询模型,以便你更好地了解Hibernate如何执行JPQL或Criteria API查询。
Hibernate 5、4和3
在Hibernate 6之前,实体查询的执行方式如下。

Criteria API将简单地生成一个JPQL,Hibernate根据其HQL语法对其进行解析,以生成底层数据库特定的SQL查询。
让Criteria API生成JPQL,然后再进行解析,效率并不高,所以我们设计了一个更好的模型来处理这些实体查询。
Hibernate 6 SQL - 语义查询模型
从Hibernate 6开始,这就是实体查询的生成方式。

JPQL被编译成SQM,而Criteria API则立即创建了SQM节点,因此提高了其效率。
要看到SQM是如何建立的,你必须将org.hibernate.orm.query.sqm.ast 记录器设置为debug 。
<logger name="org.hibernate.orm.query.sqm.ast" level="debug"/>
并且,在执行以下JPQL窗口函数查询时。
List<StatementRecord> records = entityManager.createQuery("""
SELECT
ROW_NUMBER() OVER(
PARTITION BY at.account.id
ORDER BY at.createdOn
) AS nr,
at,
SUM(at.amount) OVER(
PARTITION BY at.account.id
ORDER BY at.createdOn
) AS balance
FROM AccountTransaction at
ORDER BY at.id
""", StatementRecord.class)
.unwrap(Query.class)
.setTupleTransformer((Object[] tuple, String[] aliases) -> new StatementRecord(
longValue(tuple[0]),
(AccountTransaction) tuple[1],
longValue(tuple[2])
))
.getResultList();
Hibernate要记录下面的语义查询模型树。
o.h.o.q.s.ast - SqmStatement Tree :
-> [select]
-> [query-spec]
-> [select]
-> [selection(nr)]
<- [selection(nr)]
-> [selection]
-> [root] - `com.vladmihalcea.book.hpjp.hibernate.query.window.AccountTransaction(at)`
<- [root] - `com.vladmihalcea.book.hpjp.hibernate.query.window.AccountTransaction(at)`
<- [selection]
-> [selection(balance)]
<- [selection(balance)]
<- [select]
-> [from]
-> [root] - `com.vladmihalcea.book.hpjp.hibernate.query.window.AccountTransaction(at)`
<- [root] - `com.vladmihalcea.book.hpjp.hibernate.query.window.AccountTransaction(at)`
<- [from]
<- [query-spec]
<- [select]
Hibernate 6SqmSelectStatement 类实现了Jakarta Persistence TypedQuery 和CriteriaQuery ,并具有以下依赖性。

通过统一查询模型,Hibernate 6标准查询将能够用特定Jakarta Persistence规范不支持的功能进行扩展,就像Hibernate HQL比标准JPQL规范提供更多的功能一样。
结论
Hibernate 6提供了很多新功能,新的SQM(Semantic Query Model)是一个非常强大的API,是很多新查询功能的基础。
有了Hibernate SQM API,Hibernate就可以提供以前由Blaze Persistence提供的高级查询功能,比如LATERAL JOINs、CTE(Common Table Expressions)或Window Functions。