Evicted object still issues updates to the database in Hibernate

 ̄綄美尐妖づ 提交于 2019-12-11 03:45:12

问题


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??


回答1:


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.



来源:https://stackoverflow.com/questions/24756443/evicted-object-still-issues-updates-to-the-database-in-hibernate

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!