被驱逐的对象仍然在Hibernate中发布对数据库的更新 [英] Evicted object still issues updates to the database in Hibernate

查看:138
本文介绍了被驱逐的对象仍然在Hibernate中发布对数据库的更新的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在驱逐一个实体时遇到问题,但对其进行的更改仍然会更改数据库。这是我DAO中方法的一部分。

  @Entity 
public class Profile {
@Id
@GeneratedValue
私人长ID;

@OneToMany(cascade = CascadeType.ALL)
@JoinColumn(name =PROFILE_ID)
@LazyCollection(LazyCollectionOption.FALSE)
private List< Avatar>化身;


}

在DAO方法中:

  Profile profile = getProfile(...); 

//从休眠中清除
currentSession.evict(profile);
profile.setId(null);

(Avatar a:profile.getAvatars()){
currentSession.evict(a);
a.setId(null);
}

currentSession.save(profile); //保存一份配置文件(不更新)

之前:

  PUBLIC.PROFILE 
ID,DOMAIN,STATUS
1,test,MEMBER

PUBLIC .AVATAR
ID,NAME,PROFILE_ID
1,main,1

after method

  PUBLIC.PROFILE 
ID,DOMAIN,STATUS
1,test,会员
2,test,会员

PUBLIC.AVATAR
ID,名称,简介_ID
1,主要,无效
2,main,2

正如你所看到的,AVATAR中的原始行现在有一个空外键。



为什么?这发生在使用Unitils和Spring 的单元/集成测试中,这可能会影响Hibernate DAO的工作方式,也许。

一个内存中的H2数据库..






添加行后

  profile.setAvatars(new ArrayList<>(profile.getAvatars()); 

$ b $
$ b

所以我猜这个问题是Hibernate执行 List ,但是怎么会影响行为呢?

解决方案

编辑:首先回答很蠢,因为 @LazyCollection(LazyCollectionOption.FALSE)



我可以重现和修复,但我无法理解实际发生的情况......



首先会发生什么情况(在调试器中侦察):

由于 avatars 集合是渴望的, profile.getAvatars()完全填充,是一个Hibernat e集合(在我自己的测试中,它是一个 PersistentBag



profile 被驱逐出境,它的所有头像也被驱逐(至少在Hibernate 4.1.9 Final中)。

On currentSession.save(profile)全部都非常棒,插入了一个新的 Profile ,并且还插入了一个新的 Avatar 。但在接下来的事务提交中,Hibernate决定去做着名的 update Avatar set profile_id = null where profile_id = 1; : - (



接下来的修正:



我认为Hibernate惊讶地发现一个新实体已经有一个 PersistentBag 携带一个集合,所以我创建了一个简单的 ArrayList ,附加了当前的 Avatars ,并将它放入 profile

  List< Avatar> avatars = new ArrayList< Avatar>( ); 
for(Avatar a:profile.getAvatars()){
currentSession.evict(a); //实际上无用但无害
a.setId(null);
avatars.add(a);
}
profile.setAvatars(avatars);





所以原因似乎是 PersistentBag

code>在一个新的实体中,但我无法想象在Hibernate内部实际发生了什么s。

I have a problem where I evict an entity, but changes made to it will still change the database. This is part of the method in my DAO.

@Entity
public class Profile {
    @Id
    @GeneratedValue
    private Long id;

    @OneToMany(cascade = CascadeType.ALL)
    @JoinColumn(name = "PROFILE_ID")
    @LazyCollection(LazyCollectionOption.FALSE)
    private List<Avatar> avatars;

    ...
  }

In a DAO method:

Profile profile = getProfile(...);

// Clear from hibernate
currentSession.evict(profile);
profile.setId(null);

for (Avatar a : profile.getAvatars()) {
    currentSession.evict(a);
    a.setId(null);
}

currentSession.save(profile); // save a copy of Profile (not update)

before:

PUBLIC.PROFILE
  ID, DOMAIN, STATUS
  1, "test", "MEMBER"

PUBLIC.AVATAR
  ID, NAME, PROFILE_ID
  1, "main", 1

after method

PUBLIC.PROFILE
  ID, DOMAIN, STATUS
  1, "test", "MEMBER"
  2, "test", "MEMBER"

PUBLIC.AVATAR
  ID, NAME, PROFILE_ID
  1, "main", null
  2, "main", 2

So as you can see, the original row in AVATAR has now a null foreign key.

Why? This is happening in a unit / integration test using Unitils and Spring and this might influence how the Hibernate DAO works, maybe.

It's all in a in-memory H2 database..


After adding a line

profile.setAvatars(new ArrayList<>(profile.getAvatars());

it works ...

So I guess the problem was Hibernate's implementation of List, but how could that affect the behavior??

解决方案

EDIT : First answer was stupid because of @LazyCollection(LazyCollectionOption.FALSE)

I could reproduce and fix but I cannot understand what actually happens under the hood ...

First what happens (spyed under debugger):

As avatars collection is eager, profile.getAvatars() is fully populated and is a Hibernate collection (in my own tests, it is a PersistentBag)

When profile is evicted, all its avatars are also evicted (at least with Hibernate 4.1.9 Final).

On currentSession.save(profile) all is marvelous, a new Profile is inserted and also a new Avatar. But on following transaction commit, Hibernate decides to do the famous update Avatar set profile_id = null where profile_id = 1; :-(

Next the fix :

I supposed that Hibernate is surprised to find a new entity already having a PersistentBag to carry a collection. So I created a simple ArrayList, appended current Avatars to it, and put it into profile :

List<Avatar> avatars = new ArrayList<Avatar>();
for (Avatar a : profile.getAvatars()) {
    currentSession.evict(a); // in fact useless but harmless
    a.setId(null);
    avatars.add(a);
}
profile.setAvatars(avatars);

And ... all is fine, Hibernate no longer emits the offending update !

So the cause seems to be a PersistentBag in a new entity, but i cannot imagine what actually happens in Hibernate internals.

这篇关于被驱逐的对象仍然在Hibernate中发布对数据库的更新的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆