Java.Hibernate.Middle.What is the difference between @OneToMany(mappedBy=…) vs. @JoinColumn?

✅ Short Answer

  • @OneToMany(mappedBy=...) marks the inverse side of a bidirectional relationship → it tells JPA the parent does not own the foreign key.
  • @JoinColumn marks the owning side → it defines where the foreign key is stored in the database.

🔎 Detailed Explanation


🔹 @JoinColumn

  • Used on the owning side of the relationship, usually on @ManyToOne or unidirectional @OneToMany.
  • Defines the physical foreign key column in the database.
  • Example on owning side (ChildEntity):
@ManyToOne
@JoinColumn(name = "parent_id") // child owns the FK
private ParentEntity parent;

✅ Here, ChildEntity is the owning side → it has the parent_id column in its table.

🔹 @OneToMany(mappedBy=…)

  • Used on the inverse side of a bidirectional relationship → parent’s collection references the owning side’s field.
  • Tells JPA which field in the child owns the foreign key.
  • Example on inverse side (ParentEntity):
@OneToMany(mappedBy = "parent") // "parent" field in ChildEntity owns the FK
private List<ChildEntity> children;

✅ mappedBy points to the field name (parent) in the owning entity.

🔹 What happens without mappedBy?
If you write @OneToMany without mappedBy, JPA assumes the parent owns the relationship and creates a join table, not a foreign key → leads to inefficient schema:

@OneToMany
private List<ChildEntity> children; // creates join table Parent_Children

🔹 Putting it all together: Bidirectional Mapping

@Entity
public class ParentEntity {
    @OneToMany(mappedBy = "parent") // inverse side
    private List<ChildEntity> children;
}

@Entity
public class ChildEntity {
    @ManyToOne
    @JoinColumn(name = "parent_id") // owning side → foreign key in child table
    private ParentEntity parent;
}

📊 Comparison Table

Feature@JoinColumn@OneToMany(mappedBy=…)
Owns the relationship?✅ Yes (defines foreign key)❌ No (inverse, points to owner)
Defines foreign key?✅ Yes❌ No
Creates join table?❌ No❌ Not by itself, but missing mappedBy causes join table
Used on which side?Owning side (usually @ManyToOne)Inverse side (usually @OneToMany)

📌 Key Takeaways

✅ Use @JoinColumn to define where the foreign key physically exists → owning side.
✅ Use @OneToMany(mappedBy=...) to mark the inverse side, pointing to the owning side’s field.
✅ Bidirectional mappings need one owning side + one inverse side for proper persistence behavior.

Posted in Без рубрики | Comments Off on Java.Hibernate.Middle.What is the difference between @OneToMany(mappedBy=…) vs. @JoinColumn?

Java.Hibernate.Middle.How do you map an embeddable object in Hibernate?

✅ Short Answer

In Hibernate/JPA, you map an embeddable object using @Embeddable on the value class, and @Embedded on the owning entity’s field → the embeddable’s fields become columns in the entity’s table.

🔎 Detailed Explanation

🔹 Embeddables are reusable value objects:

  • They don’t have their own table → they’re embedded into the owning entity’s table.
  • Great for grouping related fields (e.g., address, monetary amount, coordinates) into a clean object.
  • Avoids cluttering entity classes with dozens of flat fields.

🔹 Steps to map an embeddable

✅ 1) Create the embeddable class

@Embeddable
public class Address {
    private String street;
    private String city;
    private String zipCode;
}

✅ 2) Add the embeddable to an entity

@Entity
public class User {
    @Id
    private Long id;

    private String name;

    @Embedded
    private Address address; // fields of Address become columns in User table
}

🔹 What happens in the database?

  • Hibernate maps User into a single table with columns:
    • id, name, street, city, zip_code.

🔹 Customizing column names with @AttributeOverrides
If you embed the same embeddable twice or want custom column names, use @AttributeOverrides:

@Embedded
@AttributeOverrides({
    @AttributeOverride(name = "street", column = @Column(name = "home_street")),
    @AttributeOverride(name = "city", column = @Column(name = "home_city")),
    @AttributeOverride(name = "zipCode", column = @Column(name = "home_zip"))
})
private Address homeAddress;

@Embedded
@AttributeOverrides({
    @AttributeOverride(name = "street", column = @Column(name = "work_street")),
    @AttributeOverride(name = "city", column = @Column(name = "work_city")),
    @AttributeOverride(name = "zipCode", column = @Column(name = "work_zip"))
})
private Address workAddress;

✅ This allows you to embed the same class multiple times in an entity.

📊 Benefits of Embeddables

✅ Improves code reuse and domain model clarity → avoids repetition.
✅ Keeps the database normalized without creating extra tables.
✅ Supports nested embedding → embeddables can themselves embed other embeddables.

📌 Key Takeaways

✅ Annotate reusable value objects with @Embeddable, and use @Embedded in entities.
✅ Embeddables have no separate table → their fields become columns of the owning entity.
✅ Use @AttributeOverrides to control or disambiguate column names.

Posted in Без рубрики | Comments Off on Java.Hibernate.Middle.How do you map an embeddable object in Hibernate?

Java.Hibernate.Middle.How do you map a many-to-many relationship with extra columns?

✅ Short Answer

To map a many-to-many relationship with extra columns in the join table, you can’t use plain @ManyToMany.
Instead, you must model the join table as a separate entity with two @ManyToOne relationships — this is called an association entity (or link entity).

🔎 Detailed Explanation

🔹 Why doesn’t @ManyToMany work?

  • JPA’s @ManyToMany creates a join table, but doesn’t let you add extra columns — it only maps the two foreign keys.
  • As soon as you need attributes in the join table (e.g., quantity, timestamp), you must model it explicitly.

🧑‍💻 Example: Students enrolled in Courses

You want to store enrollmentDate in the join table between Student and Course.

@Entity
public class Enrollment {
    @EmbeddedId
    private EnrollmentId id;

    @ManyToOne
    @MapsId("studentId")
    private Student student;

    @ManyToOne
    @MapsId("courseId")
    private Course course;

    private LocalDate enrollmentDate; // extra column!
}

Composite Key for Enrollment

@Embeddable
public class EnrollmentId implements Serializable {
    private Long studentId;
    private Long courseId;

    // equals() and hashCode() required!
}

Entities with mapped enrollments

@Entity
public class Student {
    @Id
    private Long id;

    @OneToMany(mappedBy = "student", cascade = CascadeType.ALL, orphanRemoval = true)
    private List<Enrollment> enrollments = new ArrayList<>();
}

@Entity
public class Course {
    @Id
    private Long id;

    @OneToMany(mappedBy = "course", cascade = CascadeType.ALL, orphanRemoval = true)
    private List<Enrollment> enrollments = new ArrayList<>();
}

🔹 What does this give you?
✅ A join table represented by Enrollment with:

  • student_id (FK)
  • course_id (FK)
  • enrollment_date (extra column)
    ✅ Ability to attach attributes to the relationship → essential for real-world scenarios.

📊 Benefits of association entity approach

✅ Adds flexibility → store relationship metadata.
✅ Supports cascade operations & orphan removal on relationships.
✅ Allows proper object modeling → no awkward DTO hacks.

📌 Key Takeaways

✅ You can’t use @ManyToMany directly with extra columns → must create an association entity.
✅ Map the association entity with @ManyToOne + @EmbeddedId (or @IdClass) for composite keys.
✅ This pattern gives you full power over join table attributes.

Posted in Без рубрики | Comments Off on Java.Hibernate.Middle.How do you map a many-to-many relationship with extra columns?

Java.Hibernate.Middle.What means orphan removal ? Give example

✅ Short Answer

Orphan removal means that if you remove a child entity from its parent’s collection, JPA will automatically delete that child entity from the database, treating it as an “orphan.”

🔎 Detailed Explanation

🔹 By default in a @OneToMany or @OneToOne relationship, if you remove a child from the parent’s collection, the child’s foreign key is set to NULL (if nullable) but the child row stays in the database.

🔹 With orphanRemoval = true, removing the child from the parent’s collection instructs Hibernate/JPA to delete the child entity entirely.

🔹 This helps ensure your object model stays in sync with the database → children not attached to any parent don’t hang around as “orphans.”

🧑‍💻 Example

@Entity
public class ParentEntity {
    @Id @GeneratedValue
    private Long id;

    @OneToMany(mappedBy = "parent", cascade = CascadeType.ALL, orphanRemoval = true)
    private List<ChildEntity> children = new ArrayList<>();
}

@Entity
public class ChildEntity {
    @Id @GeneratedValue
    private Long id;

    @ManyToOne
    @JoinColumn(name = "parent_id")
    private ParentEntity parent;
}

✅ Here, orphanRemoval=true on the parent’s @OneToMany.

Code using orphan removal:

// Load parent with 2 children
ParentEntity parent = session.find(ParentEntity.class, 1L);
ChildEntity child = parent.getChildren().get(0);

// Remove child from parent's collection
parent.getChildren().remove(child);

SQL generated with orphan removal:

delete from child_entity where id=child.id;

✅ The child is deleted from the database automatically when removed from the parent’s collection.

🔹 Without orphanRemoval
If orphanRemoval=false, the same code would just set the child’s parent_id to NULL (if allowed), leaving the row in the child table.

📌 Key Takeaways

✅ orphanRemoval=true → deleting from parent collection deletes child from DB.
✅ Ensures no “orphan” child rows remain → great for enforcing aggregate boundaries.
✅ Often used together with cascade=CascadeType.ALL for full lifecycle control of child entities.

if i write parent.getChildren().remove(child);
when it will be removed ?

✅ Short Answer

When you call parent.getChildren().remove(child), the child won’t be deleted immediately.
Instead, Hibernate schedules the delete operation to happen on the next flush — which usually occurs:
✅ Automatically at transaction commit,
✅ Or when you explicitly call entityManager.flush() or session.flush().


🔎 Detailed Explanation

🔹 JPA/Hibernate works with a persistence context, where entity changes are tracked but not instantly applied to the database.
🔹 So, when you do:

parent.getChildren().remove(child);
  • Hibernate marks the child for deletion (because of orphanRemoval=true).
  • The actual DELETE SQL won’t execute immediately.

🔹 When does it execute?
1️⃣ On flush: either explicit entityManager.flush() / session.flush(), or
2️⃣ On transaction commit: when you call transaction.commit(), Hibernate automatically flushes pending changes.


🔹 Example Timeline

transaction.begin();

ParentEntity parent = em.find(ParentEntity.class, 1L);
ChildEntity child = parent.getChildren().get(0);

parent.getChildren().remove(child); // schedules delete
// Still no DELETE SQL yet!

transaction.commit(); // triggers flush → Hibernate issues DELETE SQL:
                      // delete from child_entity where id=...

🔹 Important Notes
✅ If you rollback the transaction before commit, the pending delete is discarded → the child is not removed from the database.
✅ Hibernate batches these pending operations for efficiency.


📌 Key Takeaways

✅ Removing a child from the collection with orphanRemoval=true schedules the child for deletion.
✅ The delete happens when the persistence context flushes, typically at transaction commit.
✅ Understanding this helps avoid surprises (e.g., seeing data still present before commit).

Posted in Без рубрики | Comments Off on Java.Hibernate.Middle.What means orphan removal ? Give example

Java.Hibernate.Middle.What sql’s are executed when i select, insert, delete parent/child, especially when i need bidirectional connections ?

✅ Scenario: Mapping

You have:

@Entity
public class ParentEntity {
    @Id @GeneratedValue
    private Long id;

    @OneToMany(mappedBy = "parent", cascade = CascadeType.ALL, orphanRemoval = true)
    private List<ChildEntity> children = new ArrayList<>();
}

@Entity
public class ChildEntity {
    @Id @GeneratedValue
    private Long id;

    @ManyToOne
    @JoinColumn(name = "parent_id")
    private ParentEntity parent;
}

📥 Insert Parent + Children

Code:

ParentEntity parent = new ParentEntity();
ChildEntity child1 = new ChildEntity();
ChildEntity child2 = new ChildEntity();

child1.setParent(parent);
child2.setParent(parent);
parent.getChildren().add(child1);
parent.getChildren().add(child2);

session.persist(parent);

SQL executed:
1️⃣ INSERT parent row:

insert into parent_entity (id, ...) values (1, ...);

2️⃣ INSERT each child row with foreign key:

insert into child_entity (id, parent_id, ...) values (10, 1, ...);
insert into child_entity (id, parent_id, ...) values (11, 1, ...);

📤 Select Parent + Children

Parent alone:

ParentEntity parent = session.find(ParentEntity.class, 1L);

SQL:

select ... from parent_entity where id=1;

✅ No child data loaded if collection is LAZY → Hibernate will proxy the children.

Accessing children:

parent.getChildren().size(); // triggers child collection loading

SQL:

select ... from child_entity where parent_id=1;

🗑️ Delete Parent

session.remove(parent);

If you have cascade = CascadeType.ALL + orphanRemoval = true, Hibernate issues:

1️⃣ Delete all child rows first:

delete from child_entity where parent_id=1;

2️⃣ Delete parent row:

delete from parent_entity where id=1;

✅ This ensures referential integrity → avoids foreign key constraint violations.

🔄 Remove Child from Parent Collection

parent.getChildren().remove(child1);

If orphanRemoval = true, Hibernate issues:

delete from child_entity where id=10;

Otherwise (orphanRemoval = false), Hibernate updates the child to detach it:

update child_entity set parent_id=null where id=10;

📝 Update Child

child1.setSomeField("newValue");

Hibernate issues:

update child_entity set some_field='newValue' where id=10;

🕵️ Special Note on Bidirectional Consistency

Hibernate does not issue extra SQL to “sync” Java-side parent-child references.
It’s your responsibility to maintain consistency:

child.setParent(parent);
parent.getChildren().add(child);

📌 Key Takeaways

✅ Insert parent + children → INSERT parent → INSERT children with parent_id.
✅ Select parent → one SELECT on parent; child collection triggers separate SELECT if accessed (unless using fetch join).
✅ Delete parent → DELETE children (if cascade+orphanRemoval) → DELETE parent.
✅ Remove child from collection → DELETE child or set parent_id=null depending on orphanRemoval.
✅ Bidirectional mappings require you to sync both sides in Java objects — Hibernate does not auto-sync Java references.

Posted in Без рубрики | Comments Off on Java.Hibernate.Middle.What sql’s are executed when i select, insert, delete parent/child, especially when i need bidirectional connections ?

Java.Hibernate.Middle.How do you map a bidirectional one-to-many relationship?

✅ Short Answer

To map a bidirectional one-to-many relationship, you:
1️⃣ Add a @OneToMany(mappedBy = "...") collection on the parent side.
2️⃣ Add a @ManyToOne reference to the parent on the child side.
This creates a two-way link between parent and child entities.

🔎 Detailed Explanation

🔹 Bidirectional means:

  • Both the parent and child know about each other.
  • The child has a reference to its parent → you can navigate parent → children and child → parent.

🔹 Mapping Example

@Entity
public class ParentEntity {
    @Id
    @GeneratedValue
    private Long id;

    @OneToMany(mappedBy = "parent", cascade = CascadeType.ALL)
    private List<ChildEntity> children = new ArrayList<>();
}

@Entity
public class ChildEntity {
    @Id
    @GeneratedValue
    private Long id;

    @ManyToOne
    @JoinColumn(name = "parent_id") // foreign key in child table
    private ParentEntity parent;
}

✅ Here:

  • mappedBy="parent" on @OneToMany points to the ChildEntity.parent field → it tells JPA that the child’s parent field owns the foreign key.
  • The parent’s children collection is mapped as inverse side.

🔹 How it works in the database

  • The child table (ChildEntity) contains a parent_id column as a foreign key to the parent table (ParentEntity).
  • No join table → uses direct foreign key.

🔹 Synchronizing both sides
To keep object model consistent, you should manage both sides in your code:

ParentEntity parent = new ParentEntity();
ChildEntity child = new ChildEntity();

child.setParent(parent);
parent.getChildren().add(child);

⚠️ If you skip one side, your in-memory model may not match the database.

🔹 Key benefits of bidirectional mapping
✅ Allows navigation both from parent → children and child → parent.
✅ Great for using in queries or DTOs needing both directions.

📊 Quick Comparison

AspectBidirectional One-to-Many
Parent → children@OneToMany(mappedBy=...)
Child → parent@ManyToOne with @JoinColumn
SchemaForeign key in child table
NavigationBoth parent and child know each other

📌 Key Takeaways

✅ In bidirectional one-to-many, child owns the foreign key with @ManyToOne.
✅ Parent’s @OneToMany(mappedBy=...) defines the inverse side, pointing to the child’s parent field.
✅ Always synchronize both sides when adding/removing children → keeps in-memory model and DB consistent.

Posted in Без рубрики | Comments Off on Java.Hibernate.Middle.How do you map a bidirectional one-to-many relationship?

Java.Hibernate.Middle.How do you map a unidirectional one-to-many relationship?

✅ Short Answer

To map a unidirectional one-to-many relationship, you use @OneToMany on the “one” side without a corresponding mapping on the “many” side. You typically combine it with @JoinColumn to specify the foreign key column in the “many” table.

🔎 Detailed Explanation

🔹 Unidirectional means:

  • Only one side (the parent) knows about the relationship.
  • The child entity does not have any reference back to the parent → the relationship is not bidirectional.

🔹 Mapping Example

@Entity
public class ParentEntity {
    @Id
    @GeneratedValue
    private Long id;

    @OneToMany
    @JoinColumn(name = "parent_id") // foreign key in child table
    private List<ChildEntity> children = new ArrayList<>();
}

@Entity
public class ChildEntity {
    @Id
    @GeneratedValue
    private Long id;
    private String name;
}

🔹 What happens in the database?

  • The child table (ChildEntity) gets a parent_id foreign key column.
  • But there’s no parent field in ChildEntity Java class.
  • The relationship is owned by ParentEntity only → hence unidirectional.

🔹 Key Points about @JoinColumn:
✅ Required in unidirectional @OneToMany → otherwise JPA creates a join table (not foreign key).
✅ @JoinColumn(name = "parent_id") tells Hibernate to put the parent’s ID directly in the child table → more efficient than a join table.

🔹 Without @JoinColumn?
If you skip @JoinColumn, JPA uses a join table (like in many-to-many), which is less efficient for one-to-many.

Example:

@OneToMany
private List<ChildEntity> children; 

→ creates a join table like parententity_childentity(parententity_id, childentity_id).

📊 Comparison: Unidirectional vs. Bidirectional

AspectUnidirectional One-to-ManyBidirectional One-to-Many
Child knows parent?❌ No✅ Yes (mapped with @ManyToOne)
Simpler mapping?✅ Yes❌ Slightly more complex
NavigationOnly parent → childrenParent ↔ child

📌 Key Takeaways

✅ Use @OneToMany + @JoinColumn on the parent entity → simplest way to map unidirectional one-to-many.
✅ Avoids join tables → better performance and simpler schema.
✅ The child entity doesn’t need a reference back to the parent.

Posted in Без рубрики | Comments Off on Java.Hibernate.Middle.How do you map a unidirectional one-to-many relationship?

Java.Hibernate.Middle.When to use which instrument to solve n+1 problem ?

✅ Use JOIN FETCH when:

  • You always need the associated data in that query’s result (e.g., displaying authors and their books in a UI table).
  • You’re only fetching one collection or single-valued associations → avoids Cartesian explosion.
  • You want maximum performance with one query.

🚨 Avoid if:

  • You need to join multiple collections → can produce huge result sets with duplicated parent rows.

✅ Use EntityGraph when:

  • You want to control fetching dynamically at runtime (e.g., REST APIs where some endpoints need extra data, others don’t).
  • You prefer not to hardcode JOIN FETCH into your JPQL queries.
  • You’re using JPA 2.1 or newer.

🚨 Avoid if:

  • You need precise control over query shape beyond what EntityGraph allows.

✅ Use Batch fetching (@BatchSize) when:

  • You want to keep lazy loading but reduce N+1 overhead.
  • You load a list of parents (e.g., orders) and then later access child associations (e.g., order items).
  • Your use case includes paging or processing batches of entities.

🚨 Avoid if:

  • Your data access pattern doesn’t touch multiple proxies together → batching can’t kick in.

✅ Use Subselect fetching when:

  • You load a list of parent entities in one query, and later need their collections.
  • You want to avoid both N+1 and Cartesian product issues with JOIN FETCH.
  • Your expected parent list size is moderate (tens to low hundreds) → avoids massive IN clauses.

🚨 Avoid if:

  • Your parent list can be huge → subselect’s IN (...) clause could become inefficient or exceed database limits.

✅ Use EAGER fetching when:

  • The association is always needed, for example, small one-to-one relationships like User.profile.
  • You control entity usage tightly and know loading the association by default is safe.

🚨 Avoid if:

  • The association is a collection or large data → eager fetching can load too much data or cause performance bottlenecks.

✅ Use manual queries with WHERE IN (...) when:

  • You want precise, explicit control over fetching behavior in your service layer.
  • You have a complex access pattern not easily expressed with JOIN FETCH or EntityGraphs.

🔥 Quick cheatsheet:

ScenarioBest strategy
Need associated data every timeJOIN FETCH
Varying needs for associated dataEntityGraph
Keep lazy loading but reduce N+1 overheadBatch fetching
Loading a page of parents + their childrenSubselect fetching
One-to-one/small always-needed dataEAGER fetching
Special or complex needsManual queries
Posted in Без рубрики | Comments Off on Java.Hibernate.Middle.When to use which instrument to solve n+1 problem ?

Java.Hibernate.Middle.Give me a full list of decisions of n + 1 problem

✅ 1) Join fetches (JOIN FETCH in JPQL/HQL)

  • Load parent and associated entities in one SQL query.
  • Example:
SELECT DISTINCT a FROM Author a JOIN FETCH a.books

Pros: very effective; simple.

Cons: can cause Cartesian product explosions when fetching multiple collections.

✅ 2) Entity graphs (EntityGraph API)

  • Declaratively specify what associations to eagerly fetch without hardcoding joins in queries.
  • Example:
EntityGraph<Author> graph = em.createEntityGraph(Author.class);
graph.addAttributeNodes("books");
em.createQuery("FROM Author", Author.class)
  .setHint("javax.persistence.fetchgraph", graph)
  .getResultList();

Pros: flexible; keeps queries clean.

Cons: JPA 2.1+ only.

✅ 3) Batch fetching (@BatchSize or hibernate.default_batch_fetch_size)

  • Loads multiple lazy proxies in batches, reducing N queries to N/batchSize queries.
  • Example:
@OneToMany(fetch = FetchType.LAZY)
@BatchSize(size = 10)
private List<Book> books;

Pros: keeps lazy loading; effective for many-to-one or one-to-many.

Cons: still issues multiple queries.

✅ 4) Subselect fetching (@Fetch(FetchMode.SUBSELECT))

  • Loads collections for a list of parent entities in a single subselect query:
@OneToMany(mappedBy = "author", fetch = FetchType.LAZY)
@Fetch(FetchMode.SUBSELECT)
private List<Book> books;

Pros: single secondary query; avoids Cartesian explosion.

Cons: large parent lists can produce large IN (...) clauses.

✅ 5) Adjust fetch type to EAGER (with caution)

  • Eager associations load automatically with the parent entity.
  • Example:
@OneToMany(fetch = FetchType.EAGER)
private List<Book> books;

Pros: eliminates lazy loading delays.

Cons: dangerous — can cause unexpected massive joins or performance hits if used blindly.

✅ 6) Manual queries with WHERE IN (...)

  • Write explicit queries to load all needed associations in one go.
  • Example:
SELECT b FROM Book b WHERE b.author.id IN :authorIds

Pros: complete control.

Cons: manual; increases boilerplate.

✅ 7) Hibernate second-level cache

  • Does not solve N+1 itself but mitigates its cost by avoiding repeated DB hits for the same entities.
  • Example:
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)

Pros: useful for read-heavy apps.

Cons: adds complexity; not a direct solution.

🔥 Key takeaway:

The best way to avoid N+1 in most cases is to either use JOIN FETCH, EntityGraph, or batch/subselect fetching — depending on the data shape, query, and your tolerance for Cartesian products or large IN clauses.

Posted in Без рубрики | Comments Off on Java.Hibernate.Middle.Give me a full list of decisions of n + 1 problem

Java.Hibernate.Medium.What is subselect fetching?

🔎 What is subselect fetching?

Subselect fetching is a Hibernate-specific fetch strategy for collections (e.g., @OneToMany, @ManyToMany) that reduces the N+1 select problem in a different way than batch or join fetches.

Instead of:

  • executing N separate queries (1 per parent) for each collection,
  • or doing a single join query that risks Cartesian products,

Hibernate with subselect will:
1️⃣ Load your list of parent entities (e.g., 20 authors).
2️⃣ When you access the collection on any one of those parents, Hibernate triggers one secondary query with a WHERE parent_id IN (...) subselect, fetching collections for all the parents in the original list.


🔎 Example:

1️⃣ Load authors:

SELECT * FROM authors LIMIT 20;

2️⃣ Later, you access author.getBooks() on any of those 20 authors → Hibernate issues a single subselect:

SELECT * FROM books WHERE author_id IN (1, 2, 3, ..., 20);

That one query populates the collections for all 20 authors → solving the N+1 problem.

✅ How do you enable subselect fetching?

Use Hibernate’s @Fetch(FetchMode.SUBSELECT) annotation on your collection mapping:

@Entity
public class Author {
    @OneToMany(mappedBy = "author", fetch = FetchType.LAZY)
    @Fetch(FetchMode.SUBSELECT) // Hibernate-specific
    private List<Book> books;
}

✅ How is it different from batch fetching?

  • Batch fetching groups proxies in fixed-size batches (e.g., 10), issuing multiple small queries as needed.
  • Subselect fetching triggers a single query with a subselect covering all parents loaded in the original query, loading all collections at once.

✅ How is it different from join fetching?

  • Join fetch loads parents and collections in one big SQL query with a JOIN, but can cause duplicate parent rows (Cartesian explosion).
  • Subselect fetch loads collections in a separate single query, avoiding duplication and keeping parent query and collection query separate.

🚨 Caveats:

  • Subselect fetching only works if you load a collection of parents (e.g., List<Author>), not a single parent entity.
  • Large IN (...) lists (hundreds or thousands of IDs) may hurt performance or exceed database limits.

🔥 Summary:

Subselect fetching is a Hibernate strategy that issues one additional query with a WHERE parent_id IN (...) subselect, loading all collections for a set of parents in a single query and avoiding the classic N+1 problem.

Posted in Без рубрики | Comments Off on Java.Hibernate.Medium.What is subselect fetching?