休眠:具有相同标识符值的不同对象已与会话关联

2022-09-03 05:18:44

可能的重复:
休眠错误:org.hibernate.NonUniqueObjectException:具有相同标识符值的不同对象已与会话关联

当我使用 DAO.update(userbean) 时,抛出异常:具有相同标识符值的不同对象已与会话关联session.SaveOrUpdate(e);

函数如下:

    public E save(E e) {
    Session session = null;
    try {
        session = sessionFactory.openSession();
        log.debug("session="+session.hashCode()+" save "+e);
        session.SaveOrUpdate(e);  //here throws exception 
        session.flush();
    }
    catch (Exception e1) {
        log.err("Cannot open hibernate session "+ e1.getMessage()+" cause : "+e1.getCause());
        e1.printStackTrace();
    }
    finally { if ( session != null ) session.close(); session = null;}
    return e ;
}

用户模板是类 UserBean 的一个实例

public class UserBean{
   private List<GroupBean> groups = new ArrayList<GroupBean> ();
   private List<RoleBean> roles = new ArrayList<RoleBean> ();
}

public class GroupBean{
private List<RoleBean> roles = new ArrayList<RoleBean> ();
}

每个组bean都有一个角色列表,这些角色不会更改。

在数据库中,组和角色是多对多映射,

例如

我们有一个groupbean#1,它的角色:rolebean#1,rolebean#2;

groupbean#2,哪些角色是 rolebean#1。

现在我创建了一个新的userbean#1,它的组是groupbean#1,如果我想将角色bean#1添加到userbean#1,它会像标题描述一样抛出异常

我查看服务器.log,发现当我使用DAO.save时,saveOrUpdate顺序为:

userbean#1
|---|-----------***userbean.groups
|     |     groupbean#1
|     |         groupbean.roles
|     |             rolebean#1  # save relebean#1 the first time
|     |             ---done rolebean#1
|     |         ------done all rolebeans of group.roles
|     |     ---done groupbean#1
|     |-----------done all groupbeans of userbean.groups
|---|-----------***userbean.roles
     |      rolebean#1          # save rolebean#1 the second time, and throws exception here!
     |      ----done rolebean#1
     |      .....
     |-----------done all rolebeans of userbean.roles

异常的原因是 rolebean#1 在一个会话中保存了两次,并且它们的标识是相同的。

在函数 save(E e) 中,如果我使用

session.merge(e);

取代

session.SaveOrUpdate(e);

不会抛出异常,但角色 bean#1 与 userbean#1 无关

任何人都可以对此提出一些建议?


答案 1

如果我们能看到将角色 Bean 分配给用户和组的代码,那么确定确切原因会更容易。

通常,异常告诉我们的是,该角色 Bean 有两个版本(两个实例)。第一个被更新,然后Hibernate点击第二个,并识别它是相同的标识符,但角色的不同分离版本。

Hibernate不确定哪个是正确的,在saveOrUpdate下,它会抛出一个异常来让你知道。

Merge的合约的工作方式不同,因为它将假设您打算再次保存它(即合并我的所有更改),因此将重新附加第二个版本,合并所有更改并保存任何更新。

我已经写了关于SaveOrUpdate vs Merge的博客,其中包含一些更详细的信息来解释正在发生的事情。

如果要坚持使用 SaveOrUpdate,则需要弄清楚您在分配中正在执行的操作,从而导致将角色的不同实例分配给用户的角色集合而不是组。

否则,如果合并的效果对您有效(这符合JPA标准),请使用它。


答案 2

推荐