Card 02/ 07

GotchaDifficulty: Advanced1 min

The Collection That Only Loads Inside a Transaction

A @OneToMany collection loads fine, right up until it's touched from outside the transaction that fetched its owner — which can be as simple as one repository call finishing before your code gets around to reading the collection.

java
void accessRidesOutsideTransaction(Long id) {
    RiderEntity rider = repo.findById(id).orElseThrow();
    // repo.findById()'s own transaction already closed by the time execution gets here
    System.out.println(rider.rides.size());
}
text
OUTSIDE transaction -> LazyInitializationException: failed to lazily initialize a collection of role: rides.RiderEntity.rides: could not initialize proxy - no Session
run in a container — a real Hibernate exception, verified

A repository method carries its own short transaction by default — that's how findById runs at all without one wrapping the whole method. rider.rides is a lazy proxy, not real data yet, and by the time .size() is called, the transaction that could have filled it in is already gone. This is Spring Data JPA's failure mode specifically: Spring Data JDBC has no lazy loading to fail, because it never leaves anything unloaded in the first place — an aggregate loads in full, every time.