By WebNest Studio Engineering Team
Advanced Java Tutorial
HQL and the Criteria API
Hibernate offers two ways to write queries beyond simple get()-by-id lookups: HQL, a SQL-like query language that operates on entity names and fields instead of table and column names, and the Criteria API, a type-safe, programmatic way to build queries without writing any query language as a string at all.
HQL — Hibernate Query Language
HQL looks like SQL but is database-independent: you write from Student s where s.marks > :min, referencing the entity class name and its Java field names, and Hibernate translates it into the correct SQL dialect for whatever database is configured. This means the same HQL runs unchanged whether the underlying database is MySQL, PostgreSQL, or Oracle.
- Named/positional parameters (
:minor?1) protect against SQL injection, exactly like a JDBC PreparedStatement. - HQL supports joins, aggregate functions, GROUP BY, and subqueries, all expressed in terms of entities and their associations rather than raw tables.
- Named queries (
@NamedQuery) let you predefine and reuse an HQL string by name instead of rebuilding the string in application code every time.
The Criteria API — Type-Safe Query Building
Instead of a query string, the Criteria API builds a query object-by-object using the JPA CriteriaBuilder. Because it's built from Java code rather than a string, mistakes like a misspelled field name are caught by the compiler instead of surfacing as a runtime exception — this matters most for queries whose filters are assembled dynamically (e.g. an advanced search screen with several optional filters).
When to Use Which
HQL is usually more concise and readable for fixed, known-shape queries. The Criteria API earns its extra verbosity when a query's structure changes based on runtime conditions — for example, adding a WHERE clause only if the user actually provided that filter — since building that dynamically with string concatenation in HQL is error-prone, while Criteria composes predicates as ordinary Java objects.
Example
The same query written in HQL and with the Criteria API
// HQL
Query<Student> q = session.createQuery(
"from Student s where s.marks > :min order by s.marks desc", Student.class);
q.setParameter("min", 80);
List<Student> toppers = q.list();
// Criteria API — equivalent, fully type-safe
CriteriaBuilder cb = session.getCriteriaBuilder();
CriteriaQuery<Student> cq = cb.createQuery(Student.class);
Root<Student> root = cq.from(Student.class);
cq.select(root)
.where(cb.greaterThan(root.get("marks"), 80))
.orderBy(cb.desc(root.get("marks")));
List<Student> toppersCriteria = session.createQuery(cq).getResultList();
Hibernate: select s1_0.id, s1_0.marks, s1_0.name from student s1_0 where s1_0.marks>? order by s1_0.marks desc
Common Mistakes
- Concatenating raw user input directly into an HQL string instead of using named/positional parameters, reintroducing an injection risk.
- Confusing HQL entity/field names with actual table/column names — HQL always refers to the Java class and field names, not the SQL schema.
- Reaching for the Criteria API for every simple query, adding unnecessary verbosity where a one-line HQL string would be clearer.
- Forgetting that HQL is case-sensitive on entity and field names (since they map to real Java identifiers), unlike SQL keywords.
Exercise
Using the lesson's The same query written in HQL and with the Criteria API example, create a small implementation or design sketch that demonstrates HQL is a database-independent, entity-oriented query language similar in shape to SQL.. Add a test case or scenario that would catch Concatenating raw user input directly into an HQL string instead of using named/positional parameters, reintroducing an injection risk., and describe the expected result.
Show hints
- Start with HQL — Hibernate Query Language and compare your approach with The same query written in HQL and with the Criteria API. Identify the decision or behavior the lesson recommends.
- Walk through your scenario step by step. Confirm that it follows HQL is a database-independent, entity-oriented query language similar in shape to SQL. and that it would catch the failure described by Concatenating raw user input directly into an HQL string instead of using named/positional parameters, reintroducing an injection risk..
Quick quiz
1. Which choice is a mistake to avoid in HQL and the Criteria API?
- A. HQL is a database-independent, entity-oriented query language similar in shape to SQL.
- B. Concatenating raw user input directly into an HQL string instead of using named/positional parameters, reintroducing an injection risk.
- C. Confusing HQL entity/field names with actual table/column names — HQL always refers to the Java class and field names, not the SQL schema.
Show answer
B. Avoid this approach: Concatenating raw user input directly into an HQL string instead of using named/positional parameters, reintroducing an injection risk. The lesson recommends: HQL is a database-independent, entity-oriented query language similar in shape to SQL.
Interview questions
How would you apply the guidance in HQL — Hibernate Query Language to a real task, and what failure would you guard against?
Show answer
HQL is a database-independent, entity-oriented query language similar in shape to SQL. Apply this in HQL — Hibernate Query Language; the example The same query written in HQL and with the Criteria API shows one way to do it. Avoid Concatenating raw user input directly into an HQL string instead of using named/positional parameters, reintroducing an injection risk. and explain how your implementation or design prevents that failure.
Key Points to Remember
- HQL is a database-independent, entity-oriented query language similar in shape to SQL.
- Always use HQL parameters instead of string concatenation to avoid injection risks.
- The Criteria API builds queries as type-safe Java objects, catching mistakes at compile time.
- Prefer HQL for fixed queries; prefer Criteria for queries whose structure varies dynamically at runtime.
Practice in the playground
Write and run your own code for this topic, or start from the exercise or an example. Runs plain Java 17. Frameworks such as Spring, and databases, are not available here. Your code for each topic is kept in this browser.
Run the examples
Change an input, predict the result, then compare it with the output. Explain why the result changes.
These examples need a JDK project with their libraries on your computer, so they can be copied but not run here. Codelab runs Python, FastAPI backends with SQLite, plain Java 17 and HTML/CSS/JavaScript.
Written by
WebNest Studio Engineering Team
Practical lessons from developers working with Java, Python, React, databases and production systems.
Led by Vansh Duggal, Founder, WebNest Studio · Full-stack & software engineering