Introduction to HQL
Introduction to HQL Interview with follow-up questions
1. What is Hibernate Query Language (HQL) and how does it differ from SQL?
HQL (Hibernate Query Language) is Hibernate's object-oriented query language. It looks similar to SQL but operates on entity classes and their mapped properties rather than database tables and columns. In Hibernate 6, HQL is parsed by the SQM (Semantic Query Model) engine, which provides better validation and improved JPQL compliance.
Key differences from SQL:
| Aspect | HQL | SQL |
|---|---|---|
| Target | Entity class names and field names | Table names and column names |
| Case sensitivity | Entity/field names are case-sensitive | Usually case-insensitive |
| Joins | Traverses mapped associations (no ON clause needed) | Explicit join conditions required |
| Polymorphism | Queries on a superclass return all subclass instances | No native polymorphism |
| Result type | Java objects (or projections) | Raw rows |
Basic HQL examples:
// Select all orders (uses entity name, not table name)
List orders = session.createQuery(
"FROM Order WHERE status = :status", Order.class)
.setParameter("status", OrderStatus.PENDING)
.getResultList();
// JOIN via association path (no explicit ON clause)
List orders = session.createQuery(
"SELECT o FROM Order o JOIN o.customer c WHERE c.city = :city", Order.class)
.setParameter("city", "London")
.getResultList();
// Aggregate
Long count = session.createQuery(
"SELECT COUNT(o) FROM Order o WHERE o.status = :status", Long.class)
.setParameter("status", OrderStatus.SHIPPED)
.getSingleResult();
JPQL vs HQL: JPQL is the JPA standard subset; HQL is Hibernate's superset that adds features like INSERT ... SELECT, collection functions, and additional aggregate functions. All valid JPQL is valid HQL.
Hibernate 6 improvement: HQL now supports SELECT without FROM for scalar expressions, and the SQM engine catches type mismatches and invalid property names at parse time rather than at runtime.
Follow-up 1
Can you give an example of an HQL query?
Sure! Here's an example of an HQL query:
String hql = "FROM Employee WHERE department = :department";
Query query = session.createQuery(hql);
query.setParameter("department", "IT");
List employees = query.list();
Follow-up 2
What are the benefits of using HQL over SQL?
There are several benefits of using HQL over SQL:
- Object-oriented: HQL allows developers to work with persistent objects and their properties, making it easier to write queries that align with the object-oriented nature of the application.
- Database independence: HQL queries are translated into SQL queries by Hibernate, which means the same HQL query can be executed on different databases without modification.
- Automatic joins: HQL supports implicit joins, allowing developers to navigate relationships between entities without explicitly writing join statements.
- Caching: Hibernate can cache the results of HQL queries, improving performance by reducing database round trips.
- Polymorphism: HQL supports polymorphic queries, allowing developers to retrieve objects of different subclasses in a single query.
Follow-up 3
How does HQL handle polymorphism?
HQL handles polymorphism by allowing developers to write queries that retrieve objects of different subclasses in a single query. This is achieved using the 'FROM' clause followed by the superclass or interface name, and Hibernate automatically includes all subclasses or implementations in the query results. For example:
String hql = "FROM Animal";
Query query = session.createQuery(hql);
List animals = query.list();
Follow-up 4
What is the role of the Query interface in HQL?
The Query interface in HQL is used to create and execute queries. It provides methods for setting query parameters, executing the query, and retrieving the query results. Developers can create an instance of the Query interface using the 'createQuery' method of the Session interface, and then use the various methods provided by the Query interface to build and execute the query. For example:
String hql = "FROM Employee WHERE department = :department";
Query query = session.createQuery(hql);
query.setParameter("department", "IT");
List employees = query.list();
2. How does HQL handle associations and joins?
HQL handles associations and joins using object navigation paths rather than explicit table join conditions. Because Hibernate already knows the relationship structure from your entity mappings, you traverse associations using dot notation or the JOIN keyword.
Implicit join (dot navigation):
SELECT o FROM Order o WHERE o.customer.city = 'London'
Hibernate generates the necessary JOIN SQL automatically.
Explicit JOIN:
SELECT a FROM Author a JOIN a.books b WHERE b.genre = :genre
This joins the Author and Book entities via the books collection mapping.
JOIN FETCH — most important for interviews:
SELECT a FROM Author a JOIN FETCH a.books WHERE a.id = :id
JOIN FETCH initialises the collection in the same SQL query, preventing LazyInitializationException and the N+1 problem.
LEFT JOIN / LEFT JOIN FETCH:
SELECT a FROM Author a LEFT JOIN FETCH a.books
Returns authors even when they have no books (outer join semantics).
Full example with parameters:
List authors = session.createQuery(
"SELECT DISTINCT a FROM Author a " +
"JOIN FETCH a.books b " +
"WHERE b.publicationYear > :year",
Author.class)
.setParameter("year", 2020)
.getResultList();
Note DISTINCT is used here to deduplicate authors when a JOIN FETCH on a collection multiplies rows.
Key differences from SQL joins:
- You join on association names (e.g.,
a.books), not table names withONclauses. - The join condition (foreign key mapping) is already encoded in the
@JoinColumnor@JoinTableannotation — no need to repeat it in HQL. - HQL supports
INNER JOIN,LEFT JOIN,CROSS JOIN, andJOIN FETCH;RIGHT JOINhas limited support.
Follow-up 1
Can you provide an example of a join in HQL?
Sure! Here's an example of a join in HQL:
Let's say we have two entities: Author and Book, and there is a many-to-many association between them (an author can have multiple books, and a book can have multiple authors). The association is represented by a join table called author_book.
To perform a join in HQL, we can use the following syntax:
SELECT a FROM Author a JOIN a.books b WHERE b.title = 'Hibernate Basics'
In this example, we are selecting all authors who have a book with the title 'Hibernate Basics'. The JOIN keyword is used to specify the join between the Author and Book entities, and the a.books is the association mapping that represents the books associated with an author.
Follow-up 2
How does HQL handle eager and lazy fetching in joins?
In HQL, the fetching strategy for associations and joins can be specified using the FETCH keyword. By default, HQL uses lazy fetching for associations, which means that associated entities are loaded from the database only when they are accessed for the first time.
To specify eager fetching in HQL, we can use the FETCH keyword. For example:
SELECT a FROM Author a JOIN FETCH a.books WHERE a.id = 1
In this example, we are selecting an author with the ID 1 and eagerly fetching their associated books. This means that both the author and their books will be loaded from the database in a single query, instead of separate queries for each author and their books.
Follow-up 3
What is the difference between inner join, left join, and right join in HQL?
In HQL, the difference between inner join, left join, and right join is similar to SQL.
Inner Join: An inner join returns only the rows that have matching values in both tables being joined. In HQL, we can use the
JOINkeyword to perform an inner join.Left Join: A left join returns all the rows from the left table and the matching rows from the right table. If there is no match, NULL values are returned for the right table. In HQL, we can use the
LEFT JOINkeyword to perform a left join.Right Join: A right join returns all the rows from the right table and the matching rows from the left table. If there is no match, NULL values are returned for the left table. In HQL, we can use the
RIGHT JOINkeyword to perform a right join.
Here's an example of each join in HQL:
- Inner Join:
SELECT a FROM Author a JOIN a.books b WHERE b.title = 'Hibernate Basics'
- Left Join:
SELECT a FROM Author a LEFT JOIN a.books b WHERE b.title = 'Hibernate Basics'
- Right Join:
SELECT b FROM Book b RIGHT JOIN b.author a WHERE a.name = 'John Doe'
3. What is the syntax for inserting data using HQL?
HQL's INSERT support is limited to INSERT ... SELECT — you cannot insert literal values directly the way you can in SQL. HQL does not support INSERT INTO ... VALUES (...).
Syntax:
INSERT INTO TargetEntity (field1, field2, ...)
SELECT sourceField1, sourceField2, ...
FROM SourceEntity [WHERE condition]
Example — copy active products to an archive table:
int inserted = session.createMutationQuery(
"INSERT INTO ArchivedProduct (name, price, archivedAt) " +
"SELECT p.name, p.price, CURRENT_TIMESTAMP " +
"FROM Product p WHERE p.active = false")
.executeUpdate();
Note: In Hibernate 6 the preferred API for DML is createMutationQuery() rather than the older createQuery().executeUpdate().
Rules and restrictions:
- The target entity must have an
@Idfield. If the ID is not included in theSELECT, the ID generator is not invoked — you must include the id value explicitly from the source query, or the insert will fail. - Auto-generated
@Versionfields are set to their initial value (0 or equivalent) automatically. - Only persistent entity classes can be used; you cannot
INSERT INTOa native SQL table name.
When to use: Primarily for bulk data migration, archiving, or copying records between entities with matching shapes. For inserting new objects from the application layer, always use session.persist(entity) — it supports ID generation, lifecycle callbacks, and cascade operations.
Interview follow-up: To insert individual records, use:
Product p = new Product("Widget", new BigDecimal("9.99"));
session.persist(p); // replaces deprecated session.save()
Follow-up 1
Can you provide an example of an insert statement in HQL?
Sure! Here's an example of an insert statement in HQL:
INSERT INTO Employee (name, age, salary) VALUES ('John Doe', 30, 50000)
This statement inserts a new row into the Employee table with the values 'John Doe' for the name column, 30 for the age column, and 50000 for the salary column.
Follow-up 2
How does HQL handle bulk insert operations?
HQL provides a way to perform bulk insert operations using the INSERT INTO ... SELECT ... syntax. This allows you to insert multiple rows into a table based on the result of a select query. Here's an example:
INSERT INTO Employee (name, age, salary)
SELECT name, age, salary FROM TemporaryEmployee
In this example, the Employee table is populated with the rows from the TemporaryEmployee table.
Follow-up 3
What are the limitations of insert operations in HQL?
There are a few limitations of insert operations in HQL:
- HQL does not support inserting values directly from a subquery. You need to use the
INSERT INTO ... SELECT ...syntax to achieve this. - HQL does not support inserting multiple rows in a single insert statement. You need to use the
INSERT INTO ... SELECT ...syntax with a select query that returns multiple rows. - HQL does not support inserting values into identity columns or columns with auto-generated values. You need to exclude these columns from the insert statement or provide explicit values for them.
4. How can you update records using HQL?
HQL's UPDATE statement performs bulk updates directly in the database without loading entities into the persistence context. It is ideal for modifying many rows at once efficiently.
Syntax:
UPDATE EntityName SET property1 = :value1 [, property2 = :value2 ...] [WHERE condition]
Example:
int updatedCount = session.createMutationQuery(
"UPDATE Product p SET p.price = p.price * 1.10 WHERE p.category = :cat")
.setParameter("cat", "Electronics")
.executeUpdate();
Hibernate 6 API: Use createMutationQuery() for DML statements (replaces the older createQuery(...).executeUpdate() pattern).
Important caveats:
Bypasses the persistence context — Entities already loaded in the session are NOT updated in memory. After a bulk
UPDATE, callsession.clear()or re-fetch entities to avoid stale data.No dirty checking or lifecycle callbacks —
@PreUpdatelisteners and@Versionincrement do NOT fire for bulk HQL updates. If you use optimistic locking, include the version field manually:UPDATE Product SET price = :price, version = version + 1 WHERE id = :id AND version = :expectedVersionNo cascade — Cascaded operations defined on associations are not triggered.
When to use bulk HQL UPDATE vs. loading entities:
- Bulk HQL: updating hundreds/thousands of rows efficiently
- Load-then-modify: when you need lifecycle callbacks, cascades, or only a few entities
Example with multiple parameters:
session.createMutationQuery(
"UPDATE Employee e SET e.salary = :newSalary, e.updatedAt = CURRENT_TIMESTAMP " +
"WHERE e.department.id = :deptId AND e.salary < :threshold")
.setParameter("newSalary", 60000)
.setParameter("deptId", 5L)
.setParameter("threshold", 50000)
.executeUpdate();
Follow-up 1
Can you provide an example of an update statement in HQL?
Sure! Here's an example of an update statement in HQL:
UPDATE Employee SET salary = 50000 WHERE department = 'IT'
Follow-up 2
How does HQL handle bulk update operations?
HQL provides support for bulk update operations using the UPDATE statement. When performing a bulk update, HQL executes a single SQL UPDATE statement that affects multiple records. This can be more efficient than updating records one by one. However, it's important to note that bulk update operations in HQL do not trigger entity lifecycle events or Hibernate interceptors.
Follow-up 3
What are the limitations of update operations in HQL?
There are a few limitations to consider when using update operations in HQL:
- Update operations in HQL are not cascaded to associated entities by default. If you need to update associated entities, you may need to explicitly handle them.
- HQL update operations do not trigger entity lifecycle events or Hibernate interceptors.
- HQL update operations bypass the second-level cache, so you need to be cautious when updating a large number of records.
- HQL update operations may not be supported for all database-specific features or syntax. It's important to consult the Hibernate documentation or database-specific documentation for any limitations or considerations.
5. What is the syntax for deleting records using HQL?
HQL's DELETE statement performs bulk deletes directly in the database without loading entities into memory. It is more efficient than loading entities one by one and calling session.remove().
Syntax:
DELETE FROM EntityName [WHERE condition]
(FROM is optional — DELETE EntityName WHERE ... is also valid.)
Example:
int deletedCount = session.createMutationQuery(
"DELETE FROM AuditLog a WHERE a.createdAt < :cutoff")
.setParameter("cutoff", LocalDate.now().minusYears(2))
.executeUpdate();
Hibernate 6 API: Use createMutationQuery() for DML statements.
Critical caveats:
Bypasses the persistence context — Entities already in the session cache are not evicted. Call
session.clear()after a bulk delete if you might access those entities again in the same session.No cascade — Associations annotated with
cascade = CascadeType.REMOVEororphanRemoval = trueare not processed. If children exist and have a NOT NULL foreign key, the database will throw a constraint violation. Delete children first:// Delete children first session.createMutationQuery("DELETE FROM OrderLine ol WHERE ol.order.id = :orderId") .setParameter("orderId", orderId).executeUpdate(); // Then delete parent session.createMutationQuery("DELETE FROM Order o WHERE o.id = :orderId") .setParameter("orderId", orderId).executeUpdate();No lifecycle callbacks —
@PreRemoveand@PostRemovelisteners do not fire.
When to prefer bulk DELETE: For large-scale cleanup operations (archiving, purging old records). For a handful of entities where cascades and callbacks matter, load them and call session.remove(entity) instead.
Follow-up 1
Can you provide an example of a delete statement in HQL?
Sure! Here's an example of a delete statement in HQL:
DELETE FROM Employee WHERE id = :employeeId
Follow-up 2
How does HQL handle bulk delete operations?
HQL provides support for bulk delete operations using the DELETE statement. You can delete multiple records in a single query by specifying a condition in the WHERE clause. For example:
DELETE FROM Employee WHERE department = :departmentId
Follow-up 3
What are the limitations of delete operations in HQL?
There are a few limitations to be aware of when using delete operations in HQL:
- HQL does not support cascading deletes by default. You need to explicitly handle cascading deletes using appropriate mappings.
- HQL does not support joins in delete statements. If you need to delete records based on a condition involving multiple tables, you may need to use subqueries.
- HQL does not support deleting records from multiple tables in a single query. You need to execute separate delete statements for each table.
- HQL does not support returning the number of affected rows after a delete operation. If you need to know the number of deleted records, you can execute a separate count query before and after the delete operation.
Live mock interview
Mock interview: Introduction to HQL
- Read your scene and goals
- Talk it out; goals tick off live
- Get a score and stronger lines
Your voice and your AI key never touch our servers; the key stays in this browser and is sent only to Google. Only your round scores are saved to track progress.