java – hibernate乐观锁和集合的麻烦
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了java – hibernate乐观锁和集合的麻烦,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含6365字,纯文字阅读大概需要10分钟。
内容图文
![java – hibernate乐观锁和集合的麻烦](/upload/InfoBanner/zyjiaocheng/784/41984662059e4347867b6c474c750c77.jpg)
我在使用乐观锁定方面遇到了麻烦.我有一个持久对象,版本号.我希望只有在我的持久对象“真正”更新时才会增加此版本号,这意味着当一个或多个字段被修改或者在数据库中修改了在我的实体中使用@ManyToOne或@OneToMany注释映射的集合时.
发生的情况是,只有当我的实体中直接包含的字段发生更改时才会增加版本,而不会在集合发生更改时增加.
注意:我在实体注释中添加了select-before-update.不知道它是否会改变集合版本控制的行为!
我还有一个字段不应该影响我的实体中的版本,我在其上放置了@OptimisticLock(exclude = true)注释.
有谁知道我怎么可能尝试使我的版本工作?根据我在几个论坛上读到的内容,当集合发生变化时,版本号应该会自动增加.为什么不是我的情况呢?任何的想法?
解决方法:
只有单向集合更改才会传播到父实体版本as explained in this article.因为您使用的是双向关联,所以@ManyToOne将控制此关联,因此在父级集合中添加/删除实体不会影响父实体版本.
但是,您仍然可以将更改从子实体传播到父实体.这要求您在修改子实体时传播OPTIMISTIC_FORCE_INCREMENT锁.
This article详细解释了您应该如何实现这样一个用例.
简而言之,您需要让所有实体实现RootAware接口:
public interface RootAware<T> {
T root();
}
@Entity(name = "Post")
@Table(name = "post")
public class Post {
@Id
private Long id;
private String title;
@Version
private int version;
//Getters and setters omitted for brevity
}
@Entity(name = "PostComment")
@Table(name = "post_comment")
public class PostComment
implements RootAware<Post> {
@Id
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
private Post post;
private String review;
//Getters and setters omitted for brevity
@Override
public Post root() {
return post;
}
}
@Entity(name = "PostCommentDetails")
@Table(name = "post_comment_details")
public class PostCommentDetails
implements RootAware<Post> {
@Id
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
@MapsId
private PostComment comment;
private int votes;
//Getters and setters omitted for brevity
@Override
public Post root() {
return comment.getPost();
}
}
然后,您需要两个事件侦听器:
public static class RootAwareInsertEventListener
implements PersistEventListener {
private static final Logger LOGGER =
LoggerFactory.getLogger(RootAwareInsertEventListener.class);
public static final RootAwareInsertEventListener INSTANCE =
new RootAwareInsertEventListener();
@Override
public void onPersist(PersistEvent event) throws HibernateException {
final Object entity = event.getObject();
if(entity instanceof RootAware) {
RootAware rootAware = (RootAware) entity;
Object root = rootAware.root();
event.getSession().lock(root, LockMode.OPTIMISTIC_FORCE_INCREMENT);
LOGGER.info("Incrementing {} entity version because a {} child entity has been inserted", root, entity);
}
}
@Override
public void onPersist(PersistEvent event, Map createdAlready)
throws HibernateException {
onPersist(event);
}
}
和
public static class RootAwareInsertEventListener
implements PersistEventListener {
private static final Logger LOGGER =
LoggerFactory.getLogger(RootAwareInsertEventListener.class);
public static final RootAwareInsertEventListener INSTANCE =
new RootAwareInsertEventListener();
@Override
public void onPersist(PersistEvent event) throws HibernateException {
final Object entity = event.getObject();
if(entity instanceof RootAware) {
RootAware rootAware = (RootAware) entity;
Object root = rootAware.root();
event.getSession().lock(root, LockMode.OPTIMISTIC_FORCE_INCREMENT);
LOGGER.info("Incrementing {} entity version because a {} child entity has been inserted", root, entity);
}
}
@Override
public void onPersist(PersistEvent event, Map createdAlready)
throws HibernateException {
onPersist(event);
}
}
您可以注册如下:
public class RootAwareEventListenerIntegrator
implements org.hibernate.integrator.spi.Integrator {
public static final RootAwareEventListenerIntegrator INSTANCE =
new RootAwareEventListenerIntegrator();
@Override
public void integrate(
Metadata metadata,
SessionFactoryImplementor sessionFactory,
SessionFactoryServiceRegistry serviceRegistry) {
final EventListenerRegistry eventListenerRegistry =
serviceRegistry.getService( EventListenerRegistry.class );
eventListenerRegistry.appendListeners(EventType.PERSIST, RootAwareInsertEventListener.INSTANCE);
eventListenerRegistry.appendListeners(EventType.FLUSH_ENTITY, RootAwareUpdateAndDeleteEventListener.INSTANCE);
}
@Override
public void disintegrate(
SessionFactoryImplementor sessionFactory,
SessionFactoryServiceRegistry serviceRegistry) {
//Do nothing
}
}
然后通过Hibernate配置属性提供RootAwareFlushEntityEventListenerIntegrator:
configuration.put(
"hibernate.integrator_provider",
(IntegratorProvider) () -> Collections.singletonList(
RootAwareEventListenerIntegrator.INSTANCE
)
);
现在,当您修改PostCommentDetails实体时:
PostCommentDetails postCommentDetails = entityManager.createQuery(
"select pcd " +
"from PostCommentDetails pcd " +
"join fetch pcd.comment pc " +
"join fetch pc.post p " +
"where pcd.id = :id", PostCommentDetails.class)
.setParameter("id", 2L)
.getSingleResult();
postCommentDetails.setVotes(15);
父Post实体版本也被修改:
SELECT pcd.comment_id AS comment_2_2_0_ ,
pc.id AS id1_1_1_ ,
p.id AS id1_0_2_ ,
pcd.votes AS votes1_2_0_ ,
pc.post_id AS post_id3_1_1_ ,
pc.review AS review2_1_1_ ,
p.title AS title2_0_2_ ,
p.version AS version3_0_2_
FROM post_comment_details pcd
INNER JOIN post_comment pc ON pcd.comment_id = pc.id
INNER JOIN post p ON pc.post_id = p.id
WHERE pcd.comment_id = 2
UPDATE post_comment_details
SET votes = 15
WHERE comment_id = 2
UPDATE post
SET version = 1
where id = 1 AND version = 0
PostComment实体也是如此.
即使您插入一个新的子实体,它也可以工作:
Post post = entityManager.getReference(Post.class, 1L);
PostComment postComment = new PostComment();
postComment.setId(3L);
postComment.setReview("Worth it!");
postComment.setPost(post);
entityManager.persist(postComment);
Hibernate管理以正确地增加父实体:
SELECT p.id AS id1_0_0_ ,
p.title AS title2_0_0_ ,
p.version AS version3_0_0_
FROM post p
WHERE p.id = 1
INSERT INTO post_comment (post_id, review, id)
VALUES (1, 'Worth it!', 3)
UPDATE post
SET version = 3
WHERE id = 1 AND version = 2
它在删除子实体时也有效:
PostComment postComment = entityManager.getReference(PostComment.class, 3l);
entityManager.remove(postComment);
Hibernate也在这个用例中管理增加父实体:
SELECT pc.id AS id1_1_0_ ,
pc.post_id AS post_id3_1_0_ ,
pc.review AS review2_1_0_
FROM post_comment pc
WHERE pc.id = 3
SELECT p.id AS id1_0_0_ ,
p.title AS title2_0_0_ ,
p.version AS version3_0_0_
FROM post p
WHERE p.id = 1
DELETE FROM post_comment
WHERE id = 3
UPDATE post
SET version = 4
WHERE id = 1 and version = 3
内容总结
以上是互联网集市为您收集整理的java – hibernate乐观锁和集合的麻烦全部内容,希望文章能够帮你解决java – hibernate乐观锁和集合的麻烦所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。