TLDR ⚡ Since Hibernate 6 (2022), the Semantic Query Model (SQM) replaced the old JPQL-parsing pipeline, making queries more efficient and unlocking advanced SQL capabilities natively. If you're still on older Hibernate versions, here's why upgrading is worth it!
🧠 WHAT IS SQM?
SQM (Semantic Query Model) is Hibernate's internal query representation layer, introduced in Hibernate 6.
Before SQM, the flow was clunky:
Criteria API → generates JPQL → parsed → SQL
With SQM, the flow is clean and direct:
JPQL → compiled to SQM → SQL Criteria API → directly builds SQM nodes → SQL
Think of SQM as the universal AST (Abstract Syntax Tree) for all Hibernate queries — a single, unified model that powers both JPQL and Criteria API, while going beyond the Jakarta Persistence spec.
🔑 3 KEY POINTS
1️⃣ CRITERIA API NO LONGER GENERATES JPQL
Previously, Criteria API was just a JPQL generator — inefficient by design. With SQM, Criteria API builds query nodes directly, skipping the JPQL generation step entirely. Less overhead, cleaner execution.
2️⃣ DEBUG YOUR QUERIES WITH THE SQM LOGGER
You can visualize the full SQM tree by enabling this logger:
💡 This outputs a full tree representation of how Hibernate interprets your query internally — a game changer for debugging complex queries and understanding what Hibernate is really doing under the hood!
3️⃣ ADVANCED SQL FEATURES ARE NOW FIRST-CLASS CITIZENS
SQM enables powerful SQL features like Window Functions, LATERAL JOINs, and CTEs — previously only available via third-party libraries like Blaze Persistence. Here's a real example:
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();
🔎 Notice the ROW_NUMBER() and SUM() OVER() window functions used directly in JPQL — this is pure SQM power!
🎯 TAKEAWAYS
✅ SQM is not new
✅ Criteria API is faster
✅ Window Functions, CTEs, LATERAL JOINs are now natively supported
✅ Use the SQM logger during development to debug and understand your queries at a deeper level
✅ SQM goes beyond Jakarta Persistence spec
📚 CREDIT
Full credit to Vlad Mihalcea (Java Champion) for the original deep-dive article published in 2022 ! 🏆
#Java #Hibernate #JPA #SQM
FYI: prep Java Certification: https://www.udemy.com/course/ocp-oracle-certified-professional-java-developer-prep/?referralCode=54114F9AD41F127CB99A