Now that I’ve spent several hours without any satisfying result trying to understand and fix a problem I encounter with Hibernate’s 2nd level cache I hope I can find help here. I’ve read almost every blogpost but am still not able to built a proper caching solution.
The issue is, that when I want to access a collection from a cached entity, where the collection is set to fetch = FetchType.LAZY, Hibernate throws a LazyInitializationException: failed to lazily initialize a collection of role, although the entities inside the collection are properly cached during the first time the parent entity is requested due to overriding the lazy load via an EntityGraph.
Briefly in advance: when the 1:m collection’s fetch type is set to EAGER everything works fine.
So here is the setup:
- Post:
@Entity
@Access(AccessType.FIELD)
@org.hibernate.annotations.Cache(region = "post-cache",
usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
@Table(name = "post")
public class Post implements Serializable {
// ...
@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
@OneToMany(mappedBy = "post",
fetch = FetchType.LAZY,
cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH})
private List<PostComment> postComments = new ArrayList<>();
// ...
}
- PostComment:
@Entity
@Access(AccessType.FIELD)
@org.hibernate.annotations.Cache(region = "post-comment-cache",
usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
@Table(name = "post_comment")
public class PostComment implements Serializable {
// ...
}
- PostRepository:
public interface PostRepository extends JpaRepository<Post, Long> {
@EntityGraph(type = EntityGraph.EntityGraphType.FETCH, attributePaths = {
"postComments"
})
Optional<Post> findById(Long id);
}
Since I use SpringBoot I utilize JpaRepository to gain easy database access. As you can see, I override the default fetching behavior for the postComments collection via EntityGraph.EntityGraphType.FETCH. The first time I request a Post entity everything works as expected:
Post post = postRepository.findById(1L).get();
Hibernate puts the Post into its 2nd level cache as well as all associated PostComment in their corresponding cache. I can even demand a PostComment and Hibernate will take it from the cache:
PostComment postComment = postCommentRepository.findById(1L).get();
So at least for my understanding, at this point everything is fine. But when I want to request the recently cached Post a second time and then access the postComments collection, Hibernate is not able to build the collection out from the cache. It tries, but fails with a LazyInitializationException:
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.example.Post.postComments: could not initialize proxy - no Session
And that’s the point where I am stuck.
- Can somebody please tell me, why this happens, although all related entities are cached properly?
- And why is everything working when collections are set to eager fetching by default (which is no option at all)?
- And as a last point: why does this not affect query caches? (Query caches work as expected without any further modification of the parent entity, I don’t even have to annotate the postComments collection.)
Many thanks for any help