Hibernate

31 posts in this section

Entity Graphs and Batch Loading: Precision Fetching

The Problem @EntityGraph Solves JOIN FETCH in @Query solves N+1 but creates inflexibility: the fetch plan is baked into the query. Two different use cases — an order detail page (needs items + customer) and an order list page (needs only customer) — require two different queries with different JOIN FETCHes. @EntityGraph separates the fetch plan from the query. You define what to load at the call site, and Spring Data JPA generates the appropriate JOIN.

Continue reading »

Entity Lifecycle States: Transient, Managed, Detached, Removed

Introduction Every JPA entity is always in one of four states. The state determines whether Hibernate is tracking the entity, whether changes are detected automatically, and what operations are valid. Understanding these states explains a large class of JPA bugs — especially the dreaded LazyInitializationException and detached entity errors. The Four States new Customer() │ │ persist / save() ▼ TRANSIENT ──────────────────────► MANAGED (not tracked) (tracked by persistence context) │ │ evict / clear / close ▼ DETACHED (no longer tracked) │ │ merge() ▼ MANAGED (re-attached) MANAGED ─── remove / delete() ──► REMOVED (delete scheduled, still in context) 1.

Continue reading »

Fetch Types: EAGER vs LAZY Loading

Introduction Every relationship in JPA has a fetch type: either EAGER (load immediately with the parent) or LAZY (load only when accessed). The defaults are counterintuitive, and getting fetch types wrong is one of the top causes of performance problems and LazyInitializationException in JPA applications. Default Fetch Types Annotation Default fetch type Performance risk @ManyToOne EAGER Loads related entity on every query — can be expensive @OneToOne EAGER Same — loads profile/address on every customer load @OneToMany LAZY Correct default — collections are only loaded when needed @ManyToMany LAZY Correct default The defaults for @ManyToOne and @OneToOne are EAGER — a poor choice that the JPA spec made for historical reasons.

Continue reading »

Inheritance Strategies: SINGLE_TABLE, JOINED, TABLE_PER_CLASS

Introduction Object-oriented code uses inheritance to share behaviour. Relational databases have no concept of inheritance. JPA bridges this gap with three strategies for mapping a class hierarchy to tables. Understanding when each is appropriate prevents schema headaches and performance problems. The Domain Example An e-commerce system has different types of discount: Discount (abstract) ├── PercentageDiscount (e.g., 10% off) └── FixedAmountDiscount (e.g., $5 off) All discounts share: id, name, validFrom, validUntil. PercentageDiscount adds: percentage (e.

Continue reading »

Introduction to JPA, Hibernate, and Spring Data JPA

Introduction Every Spring Boot application that touches a relational database eventually encounters three terms used almost interchangeably: JPA, Hibernate, and Spring Data JPA. They are related but distinct, and understanding the difference is essential before writing a single line of mapping code. This article explains what each one is, how they fit together, and why this stack is the dominant approach to Java database access. The Problem: Object-Relational Impedance Mismatch Java applications work with objects: classes, inheritance, collections, references.

Continue reading »

Many-to-Many Relationships: @ManyToMany and Join Tables

Introduction A many-to-many relationship means records in table A can relate to many records in table B, and vice versa. Products have many tags; tags apply to many products. In SQL this requires a join table. In JPA, @ManyToMany and @JoinTable handle this automatically — but when you need extra data on the join (like a creation date or a relevance score), you need a different approach. Simple @ManyToMany: Product and Tag products (*) ──── product_tags ──── (*) tags The product_tags join table has two columns: product_id and tag_id.

Continue reading »

One-to-Many and Many-to-One: The Most Common Relationship

Introduction The one-to-many relationship is the most common in any domain model. An Order has many OrderItems. A Category has many Products. A Customer has many Orders. Understanding @OneToMany and @ManyToOne well — especially bidirectional mapping, collection types, and cascade configuration — is foundational to any JPA application. The Domain Example orders (1) ──────────────── (*) order_items An order has many order items. Each order item belongs to exactly one order.

Continue reading »

One-to-One Relationships: @OneToOne in Depth

Introduction A one-to-one relationship means one record in table A corresponds to exactly one record in table B. In JPA this is modelled with @OneToOne. Understanding where the foreign key lives, which side “owns” the relationship, and how cascade operations work is essential before moving to the more complex @OneToMany and @ManyToMany. The Domain Example In the e-commerce system, a Customer has one CustomerProfile containing their preferences and biography. A profile belongs to exactly one customer.

Continue reading »

Optimistic and Pessimistic Locking: Handling Concurrent Updates

The Lost Update Problem Two users edit the same product simultaneously: Time User A User B T1 Load product (price=999) Load product (price=999) T2 Change price to 899 T3 Change price to 799 T4 Save → UPDATE price=899 T5 Save → UPDATE price=799 User A’s change is silently overwritten. This is the lost update problem. Both JPA locking strategies prevent it — in different ways. Optimistic Locking with @Version Optimistic locking assumes conflicts are rare.

Continue reading »

Pagination and Sorting with Pageable, Page, and Slice

Why Pagination Matters Returning all rows from a database table is one of the most common production incidents. A query that works in development with 100 rows silently becomes a 10-second, 2 GB memory spike when production has 2 million rows. Pagination limits how many rows travel from the database to the application at a time. Spring Data JPA makes pagination a first-class feature — pass a Pageable to any repository method and get a Page<T> back.

Continue reading »