Skip to main content

JPA

Jakarta Persistence API (JPA) — object-relational mapping standard for Java

Hibernate 7 Proxies and LazyInitializationException: Causes and Cures

What a Hibernate 7 proxy actually is, the two different LazyInitializationException message templates (not one), and why naive equals() breaks against a ByteBuddy proxy. Proves loadgraph vs fetchgraph with real SQL, reproduces the Open Session in View warning masking a real failure with a live HTTP round trip, and covers hibernate.enable_lazy_load_no_trans now that it carries an @Unsafe marker.

JPA Cascade Types in Hibernate 7: A Decision Tree (Because the Wrong One Will Delete Your Data)

A startup ran cascade = CascadeType.ALL on a @ManyToOne User from their Project entity. The reasoning was sensible: they wanted deleting a project to clean everything up automatically. It worked perfectly in testing, where each project belonged to a unique test user. In production, users had multiple projects. When a user deleted their first project, Hibernate cascaded REMOVE to the User entity. The user record was deleted. The user's other projects — with all their data — were gone by FK cascade. The account was gone. Three months of work, in two SQL statements. Support ticket volume spiked. The rollback from backup took four hours. The fix was one annotation change: replace cascade = ALL with cascade = {CascadeType.PERSIST, CascadeType.MERGE}. But understanding why that specific pair — and not ALL, not REMOVE, not nothing — requires a proper decision tree.

Lazy Loading in Hibernate 7: Three Fetch Strategies, Benchmarked, with the One Most Tutorials Get Wrong

Switching from EAGER to LAZY on a @ManyToOne association made one of our REST endpoints 4x slower. That's the opposite of what every Hibernate tutorial promises, and understanding why it happened is more useful than any fetch-type cheatsheet. The endpoint served an order detail page. The Order had a @ManyToOne Customer, which was previously EAGER. Response time was ~80ms. We switched to LAZY (correctly, as a "best practice") and response time jumped to ~320ms. The reason: the EAGER mapping had been loading Customer in the same query as Order via a JOIN. LAZY replaced that with a second SELECT — and the second SELECT ran after the session had been handed to Jackson for serialisation, which triggered OSIV to keep the connection open, added latency from the extra round-trip, and eventually started failing under load when connection pool slots ran out waiting for the serialisation thread to finish. LAZY was still the right answer. The fix was a proper fetch strategy. But "switch everything to LAZY" without understanding the four fetch options and when each one earns its keep is how you trade one performance problem for a different one.

Hibernate 7 In-Memory Databases: H2, HSQLDB and Derby for Testing

A working H2 setup for Hibernate 7 unit tests, then a real side-by-side comparison against HSQLDB and Apache Derby: the Derby dialect class that no longer exists in hibernate-core, the H2 MODE= myth settled with identical DDL, a reserved-word column that fails only on H2, and a second-level-cache trap that silently changes what your test suite is actually testing.

Mastering Hibernate 7 @Immutable Entities: Performance, Safety, and Best Practices

@Immutable is a pure marker annotation that skips Hibernate's dirty-checking snapshot -- mutate a field and flush, and nothing happens: no UPDATE, no exception, just silent data loss of the in-memory change. This rewrite runs every claim against Hibernate 7.4.5 -- entity mutation, bulk HQL (rejected at translation time by default, a correction neither prior version made), collection mutation, @Immutable+@Version, and a real flush-cost measurement -- and compares the annotation head-to-head with Session.setReadOnly().

Hibernate 7 Natural IDs: What L1 and L2 Caching Actually Give You, Measured

Verified against Hibernate 7.4.5: a repeat bySimpleNaturalId lookup in the same session costs zero extra queries with no cache at all, but the bigger correction is that @NaturalIdCache populates its L2 region at insert time, not on first lookup -- so the textbook miss-then-hit story only applies to rows Hibernate didn't insert itself.

Mastering Hibernate 7 JPA Persistence Annotations: The Traps That Pass Code Review

Not another annotation catalogue: this rewrite reproduces the four JPA annotation traps that pass code review and fail in production in Hibernate 7.4.5 -- silent enum ordinal corruption, a JSON column that needs a dependency the starter doesn't provide, an access-strategy mismatch, and the equals/hashCode HashSet bug -- plus what Jakarta Persistence 3.2 actually added.

Hibernate Annotations vs. XML Mappings: Making the Right Choice in Hibernate 7

Hibernate 7.4.5 actually ships three XML mapping dialects, not two, and hbm.xml still boots unmodified with just a warning. This rewrite verifies which format wins on conflict, why xml-mapping-metadata-complete is an all-or-nothing kill switch, and what Hibernate's own mapping.xml dialect can do that JPA's orm.xml cannot.