Skip to main content

Hibernate 7

equals() and hashCode() in Hibernate: Five Patterns That Look Right and Aren’t

A team added a Product to a HashSet, called em.persist(product), and then checked whether the set contained it. The answer was false. The entity was in the database. It was in the set before the persist call. After the call it had effectively vanished from the set, even though nobody removed it. The bug is the database-generated ID in hashCode(). Before persist, id is null; hashCode() returns some value based on null. After persist, id is 42; hashCode() returns a completely different value. The entity is now sitting in the wrong bucket of the HashSet. contains() looks in the right bucket, finds nothing, returns false. The entity is lost — not from the database, just from the set — and every operation that relied on that set produces wrong answers. This is pattern one. There are four more, each equally invisible until the wrong moment. Each one looks like a reasonable implementation when you read it. The problem only shows up at runtime, often under specific conditions that don't reproduce in unit tests.

Master Java Bean Validation with Hibernate Validator 7: A Complete Guide

Have you ever spent hours debugging a "NullPointerException" or a corrupted database entry only to realize the data was malformed from the start? Manually writing if (user.getName() == null) checks across your entire service layer is not just tedious—it's a maintenance nightmare that leads to "spaghetti code." In the world of modern Java development, ensuring data integrity is paramount. This is where Java Bean Validation with Hibernate Validator 7 comes into play, providing a robust, annotation-based framework to handle constraints elegantly. In this guide, we’ll dive deep into how Hibernate Validator (the reference implementation of Jakarta Bean Validation) works with Hibernate 7 to keep your data clean and your code concise. The Problem: The "Validation Logic" Chaos Imagine a registration form for a high-traffic application. You need to ensure: The username isn't empty. The email is valid and follows global standards. The age is at least 18. The password meets complex security requirements (uppercase, digits, special characters). Without a centralized system, you end up duplicating this logic in your REST controllers, your service layer, and sometimes even at the database level using DDL constraints. This inconsistency leads to "Validation Drift," where one part of the app accepts data that another part rejects. This results in inconsistent system states, obscure runtime errors, and a poor user experience. The Agitation: Maintenance Debt and Data Corruption As your application grows, managing manual validation becomes a massive bottleneck. If the business requirement for a "valid phone number" changes to include international formats, you have to find every single if statement across dozens of files. Miss one? You’ve just introduced a security vulnerability or a data integrity issue that could poison your database for months.

HikariCP with Hibernate 7: What the Default Pool Actually Does

Spring Boot uses HikariCP by default — but confirming what that actually means takes a running app, not memory. This post measures the real default pool size, a pool-exhaustion failure that's a named exception rather than a hang, and an undocumented 2-second floor on leakDetectionThreshold that fails silently below it.

Hibernate 7 + Ehcache 3: The Second-Level Cache Claims That Don’t Hold Up

A second-level cache outlives any one Hibernate session. This post configures Ehcache 3 as Hibernate 7's L2 provider, then measures four widely-repeated claims about it against real captured test output — correcting three of them: the jakarta classifier is not about JCache's namespace, a query-cache hit costs zero SQL, and both HQL and native bulk updates leave the cache clean rather than stale.

Hibernate 7 Second-Level Cache: When to Turn It On, How to Configure Ehcache 3, and the Three Ways It Will Stale Your Data

The question that matters before enabling L2 cache is not "can I make it faster" but "can I tolerate stale data, and for how long". The cache sits between Hibernate and the database, serving data that may have been written by a different JVM process, a batch job, a DBA running a script, or another application instance. Every one of those paths can invalidate the cache without Hibernate knowing. If your answer to the staleness question is "no, I cannot tolerate any staleness" — skip L2 entirely. If the answer is "yes, but only for these entities and within these bounds" — read on. This post covers what L2 actually stores, how to configure Ehcache 3 as a JCache provider, what changed between Hibernate 6 and 7, the three specific staleness modes that catch production teams off guard, and why the query cache is almost always the wrong additional layer.

The Hibernate First-Level Cache Explained (It’s Not What You Think It Is)

Most developers who have used Hibernate for any length of time know the first-level cache exists. Ask them to describe it and you'll hear something like: "It's a cache Hibernate uses so it doesn't hit the database twice for the same row." That's technically correct, but it misses almost everything that matters. The first-level cache is not a feature you enable, a setting you tune, or an optional layer you bolt on for performance. It is the persistence context itself — always-on, transaction-scoped by default in Spring, and the thing that makes dirty checking, identity guarantees, and cascade operations possible. If you have ever used em.find(), you have used it. If you have ever hit an OutOfMemoryError in a batch job that loaded 200,000 entities, the first-level cache is why. This post is a deep look at the mechanics: what the persistence context stores, when it is consulted, how EntityKey works, and the failure modes that catch experienced developers off guard.

Stored Procedures with Hibernate 7: @NamedStoredProcedureQuery, StoredProcedureQuery, and the Traps That Bite

Merges this site's two stored-procedure articles into one, and for the first time actually runs the examples -- against HSQLDB 2.7.3 with real SQL/PSM IN/OUT/INOUT procedures instead of an unexecuted MySQL listing. Covers @NamedStoredProcedureQuery, the programmatic StoredProcedureQuery API, and Hibernate-native ProcedureCall, plus the two findings that matter most: a wrong parameter name binds positionally instead of failing, and no stored procedure call auto-flushes pending changes -- not even with addSynchronizedEntityClass declared.

The Ultimate Guide to Hibernate 7 Criteria Queries: Master Dynamic, Type-Safe Persistence

Search filters that are optionally present, one or many at a time, turn HQL into painful string concatenation. The Criteria API replaces text with Java objects instead. This rewrite proves the static metamodel (Employee_, Department_) is a real, compiler-generated class -- not a hand-typed stand-in -- by running identical queries through string paths and through the metamodel and comparing results. It also covers root.join() vs root.fetch() (the same N+1 trap as HQL's JOIN, in Criteria form), aggregation and subqueries with a genuinely counter-intuitive result, and type-safe CriteriaUpdate/CriteriaDelete. Every code block links to a real, passing test in the companion repository.

The Ultimate Guide to Hibernate Query Language (HQL) in Hibernate 7

HQL queries your domain model, not your database schema -- and that single shift explains why a typo in a field name fails instantly, why JOIN alone doesn't prevent an N+1, and why a dirty change isn't always visible the moment you expect. This rewrite covers the smallest working query, the JOIN vs JOIN FETCH trap measured in real statement counts, bulk UPDATE/DELETE bypassing the persistence context, and what each flush mode actually suppresses -- including why GenerationType.IDENTITY defeats an INSERT-based test of flush-mode behavior. Every code block and output is linked to a real, passing JUnit test and a captured transcript in the companion repository.