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