被驱逐的对象仍在Hibernate中对数据库进行更新

时间:2014-07-15 10:58:30

标签: java spring hibernate persistence unitils

我有一个问题,我驱逐一个实体,但对其进行的更改仍将更改数据库。这是我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;

    ...
  }

在DAO方法中:

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)

之前:

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

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

方法

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

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

正如您所看到的,AVATAR中的原始行现在具有空外键。

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

它全部存储在内存H2数据库中。


添加一行后

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

它有效......

所以我猜问题是Hibernate对List的实现,但是这怎么会影响行为?

1 个答案:

答案 0 :(得分:0)

编辑:由于@LazyCollection(LazyCollectionOption.FALSE)

,第一个答案是愚蠢的

我可以重现和修复,但我无法理解引擎盖下究竟发生了什么......

首先发生了什么(在调试器下窥探):

由于avatars集合非常渴望,profile.getAvatars()已完全填充且是Hibernate集合(在我自己的测试中,它是PersistentBag

profile被驱逐时,其所有化身也被驱逐(至少使用Hibernate 4.1.9 Final)。

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); // in fact useless but harmless
    a.setId(null);
    avatars.add(a);
}
profile.setAvatars(avatars);

而且......一切都很好,Hibernate不再发出令人讨厌的更新!

所以原因似乎是新实体中的PersistentBag,但我无法想象Hibernate内部实际发生了什么。