| Considering we have the following entities:
@Entity(name = "Post")
@Table(name = "post")
@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_ONLY)
public static class Post {
@Id
private Long id;
private String title;
@Version
private int version;
@OneToMany(cascade = CascadeType.ALL, mappedBy = "post", orphanRemoval = true)
@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_ONLY)
private List<PostComment> comments = new ArrayList<>();
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public List<PostComment> getComments() {
return comments;
}
public void addComment(PostComment comment) {
comments.add(comment);
comment.setPost(this);
}
}
@Entity(name = "PostComment")
@Table(name = "post_comment")
@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_ONLY)
public static class PostComment {
@Id
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
private Post post;
private String review;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Post getPost() {
return post;
}
public void setPost(Post post) {
this.post = post;
}
public String getReview() {
return review;
}
public void setReview(String review) {
this.review = review;
}
}
When the Post entity is removed, the Post.comment collection is removed as well due to orphan removal property. Unfortunately, that does not apply to the cache entryy too. READ_ONLY is the only strategy where this issue can be replicated, all other strategies work fine. Considering we have the following entities:
Session session = openSession();
Transaction transaction = session.beginTransaction();
try {
Post post = new Post();
post.setId( 1L );
post.setTitle( "Post" );
PostComment comment1 = new PostComment();
comment1.setId(1L);
comment1.setReview("JDBC part review");
post.addComment(comment1);
PostComment comment2 = new PostComment();
comment2.setId(2L);
comment2.setReview("Hibernate part review");
post.addComment(comment2);
session.persist( post );
transaction.commit();
}
catch (HibernateException expected) {
transaction.rollback();
}
finally {
session.close();
}
session = openSession();
transaction = session.beginTransaction();
try {
Post post = session.get(Post.class, 1L);
assertEquals(2, post.getComments().size());
}
catch (HibernateException expected) {
transaction.rollback();
}
finally {
session.close();
}
printCacheRegionStatistics(Post.class.getName());
printCacheRegionStatistics(Post.class.getName() + ".comments");
printCacheRegionStatistics(PostComment.class.getName());
The cache regions look like this:
When the Post entity is deleted:
session = openSession();
transaction = session.beginTransaction();
try {
Post post = session.get(Post.class, 1L);
session.delete(post);
transaction.commit();
}
catch (HibernateException expected) {
transaction.rollback();
}
finally {
session.close();
}
printCacheRegionStatistics(Post.class.getName());
printCacheRegionStatistics(Post.class.getName() + ".comments");
printCacheRegionStatistics(PostComment.class.getName());
The cache regions look like this:
The org.hibernate.bugs.ORMUnitTestCase$Post.comments region still contains an entry which is no longer valid:
|