Standard SQL uses table and column names, making queries database-specific and tightly coupled to the physical schema. When using ORM, developers want to query using Java class and field names instead, maintaining the object-oriented abstraction even during queries.
HQL (Hibernate Query Language) is an object-oriented query language that operates on entity class names and their fields instead of table and column names. HQL queries are translated by Hibernate into native SQL for the configured database dialect. Hibernate also supports Native SQL queries for database-specific features.
- HQL syntax:
from Employee e where e.department.name = :deptName— uses class and field names - Query creation:
session.createQuery("from Employee", Employee.class) - Parameter binding: Named parameters (
:paramName) or positional (?1) prevent SQL injection - Translation: Hibernate parses HQL, generates an AST, transforms it to SQL for the target dialect
- Result processing: Returns
List<Entity>orStream<Entity>automatically mapped to entities - Native SQL:
session.createNativeQuery("SELECT * FROM emp", Employee.class)for raw SQL
- Object-oriented: Queries use Java class names (
Employee) and field names (firstName) - Dialect-independent: Same HQL works on MySQL, Oracle, PostgreSQL — Hibernate handles translation
- Named parameters:
:namesyntax withsetParameter("name", value)for safe parameter binding - Aggregation: Supports
SELECT,GROUP BY,HAVING,ORDER BY, aggregate functions - Joins: Implicit path navigation (
emp.department.name) and explicit JOIN FETCH for loading associations - Native SQL fallback:
createNativeQuery()for database-specific features, stored procedures, or complex queries
- Built from: Hibernate ORM Framework — HQL is Hibernate’s query language
- Built from: EJB Query Language (EJB-QL) — HQL is the ORM successor to EJB-QL’s concept
- Related: JDBC — Native SQL in Hibernate still uses JDBC under the hood
- Builds into: Spring Data JPA — Spring Data JPA’s @Query uses JPQL (similar to HQL)
- Contrasts with: EJB-QL — EJB-QL is more limited, HQL supports richer expressions and native SQL
- N+1 with joins: Default fetching is LAZY; HQL queries without JOIN FETCH trigger N+1 queries for associations
- HQL vs SQL mindset: HQL operates on entities, not rows —
select e.firstName, e.lastNamereturnsObject[], not entities - Positional parameters:
?positional params are deprecated in Hibernate 5+ in favor of:namedparameters - Scalar queries: Aggregate results need proper typing —
query.getSingleResult()returnsLongfor COUNT, notInteger