75

我收到此错误消息:

错误:找到对集合的共享引用:Person.relatedPersons

当我尝试执行时addToRelatedPersons(anotherPerson)

person.addToRelatedPersons(anotherPerson);
anotherPerson.addToRelatedPersons(person);

anotherPerson.save();
person.save();

我的域名:

Person {

 static hasMany = [relatedPersons:Person];

}

知道为什么会这样吗?

4

12 回答 12

84

当您尝试持久化多个实体实例共享相同的集合引用(即集合标识与集合相等性对比)时,Hibernate 会显示此错误。

请注意,它表示相同的集合,而不是集合元素 - 换句话说relatedPersons,两者都person必须anotherPerson相同。也许您正在加载实体后重置该集合?或者你已经用同一个集合实例初始化了两个引用?

于 2009-11-07T20:04:46.623 回答
64

我有同样的问题。在我的例子中,问题是有人使用 BeanUtils 将一个实体的属性复制到另一个实体,所以我们最终有两个实体引用同一个集合。

鉴于我花了一些时间调查这个问题,我会推荐以下清单:

  • 寻找类似的场景entity1.setCollection(entity2.getCollection())getCollection返回对集合的内部引用(如果 getCollection() 返回集合的新实例,那么您无需担心)。

  • 查看是否clone()已正确实施。

  • 寻找BeanUtils.copyProperties(entity1, entity2)

于 2011-11-01T20:22:29.530 回答
7

实践说明。如果您尝试保存对象,例如:

Set<Folder> folders = message.getFolders();
   folders.remove(inputFolder);
   folders.add(trashFolder);
   message.setFiles(folders);
MESSAGESDAO.getMessageDAO().save(message);

您不需要将更新的对象设置为父对象:

message.setFiles(folders);

简单地保存您的父对象,例如:

Set<Folder> folders = message.getFolders();
   folders.remove(inputFolder);
   folders.add(trashFolder);
   // Not set updated object here
MESSAGESDAO.getMessageDAO().save(message);
于 2012-09-07T09:11:18.197 回答
5

在线阅读此错误的原因也可能是一个休眠错误,作为它似乎有效的解决方法,它是放一个:

session.clear()

您必须在获取数据后和提交和关闭之前清除,参见示例:

//getting data
SrReq sr = (SrReq) crit.uniqueResult();
SrSalesDetailDTO dt=SrSalesDetailMapper.INSTANCE.map(sr);
//CLEAR            
session.clear();
//close session
session.getTransaction().commit();
session.close();
return dt;

我将此解决方案用于选择数据库、更新或插入我不知道此解决方案是否可以工作或会导致问题。

我的问题等于 100%:http: //www.progtown.com/topic128073-hibernate-many-to-many-on-two-tables.html

于 2016-08-10T15:56:37.657 回答
4

我有一个很好的例子来重现这样的问题。也许我的经验有一天会帮助某人。

简洁版本

检查您的容器的@Embedded Id 是否没有可能的冲突。

长版

当 Hibernate 实例化集合包装器时,它会在内部 Map 中通过 CollectionKey 搜索已经实例化的集合。

对于具有@Embedded id 的实体,CollectionKey 包装 EmbeddedComponentType 并使用@Embedded Id 属性进行相等性检查和 hashCode 计算。

因此,如果您有两个具有相同 @Embedded Ids 的实体,Hibernate 将通过第一个键实例化并放置新集合,并为第二个键找到相同的集合。因此,具有相同 @Embedded Id 的两个实体将填充相同的集合。

例子

假设您的 Account 实体有一组惰性贷款。并且 Account 有 @Embedded Id 由几个部分(列)组成。

@Entity
@Table(schema = "SOME", name = "ACCOUNT")
public class Account {
    @OneToMany(fetch = FetchType.LAZY, mappedBy = "account")
    private Set<Loan> loans;

    @Embedded
    private AccountId accountId;

    ...
}

@Embeddable
public class AccountId {
    @Column(name = "X")
    private Long x;
    
    @Column(name = "BRANCH")
    private String branchId;
    
    @Column(name = "Z")
    private String z;

    ...
}

然后假设 Account 具有由@Embedded Id 映射的附加属性,但与其他实体分支有关系。

@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "BRANCH")
@MapsId("accountId.branchId")
@NotFound(action = NotFoundAction.IGNORE)//Look at this!
private Branch branch;

您可能没有帐户到早午餐关系 id DB 的 FK,因此 Account.BRANCH 列可以具有分支表中未显示的任何值。

根据@NotFound(action = NotFoundAction.IGNORE)相关表中是否存在值,Hibernate 将为该属性加载空值。

如果两个 Account 的 X 和 Y 列相同(这很好),但 BRANCH 不同且未显示在 Branch 表中,则 hibernate 将为两者加载null并且嵌入式 Id 将相等。

因此,两个 CollectionKey 对象将相等,并且对于不同的帐户具有相同的 hashCode。

result = {CollectionKey@34809} "CollectionKey[Account.loans#Account@43deab74]"
 role = "Account.loans"
 key = {Account@26451} 
 keyType = {EmbeddedComponentType@21355} 
 factory = {SessionFactoryImpl@21356} 
 hashCode = 1187125168
 entityMode = {EntityMode@17415} "pojo"

result = {CollectionKey@35653} "CollectionKey[Account.loans#Account@33470aa]"
 role = "Account.loans"
 key = {Account@35225} 
 keyType = {EmbeddedComponentType@21355} 
 factory = {SessionFactoryImpl@21356} 
 hashCode = 1187125168
 entityMode = {EntityMode@17415} "pojo"

因此,Hibernate 将为两个实体加载相同的 PesistentSet。

于 2020-07-30T16:50:37.863 回答
3

就我而言,我正在从其他类中复制和粘贴代码,所以我没有注意到 getter 代码写得不好:

@OneToMany(fetch = FetchType.LAZY, mappedBy = "credito")
public Set getConceptoses() {
    return this.letrases;
}

public void setConceptoses(Set conceptoses) {
    this.conceptoses = conceptoses;
}

所有参考概念,但如果你看一下 get 说letrases

于 2016-06-23T21:21:34.450 回答
3

我也遇到了同样的问题,有人用过BeanUtils.copyProperties(source, target)。这里源和目标都使用相同的集合作为属性。

所以我只是使用了如下的深拷贝..

如何在 Java 中克隆集合 - ArrayList 和 HashSet 的深拷贝

于 2017-07-25T12:28:44.693 回答
2

考虑一个实体:

public class Foo{
private<user> user;
/* with getters and setters */
}

并考虑一个业务逻辑类:

class Foo1{
List<User> user = new ArrayList<>();
user = foo.getUser();
}

这里的用户和foo.getUser()共享相同的参考。但是保存这两个引用会产生冲突。

正确的用法应该是:

class Foo1 {
List<User> user = new ArrayList<>();
user.addAll(foo.getUser);
}

这样可以避免冲突。

于 2017-08-07T09:32:03.933 回答
0

我在我的应用程序中遇到了类似的异常。查看堆栈跟踪后,很明显在FlushEntityEventListener类中引发了异常。

在 Hibernate 4.3.7 中,MSLocalSessionFactorybean 不再支持该eventListeners属性。因此,必须从单个 Hibernate 会话 bean 中显式获取服务注册表,然后设置所需的自定义事件侦听器。

在添加自定义事件侦听器的过程中,我们需要确保从相应的 Hibernate 会话中删除相应的默认事件侦听器。

如果未删除默认事件侦听器,则会出现两个针对同一事件注册的事件侦听器的情况。在这种情况下,在遍历这些侦听器时,针对第一个侦听器,会话中的任何集合都将被标记为已到达,并且在针对第二个侦听器处理相同的集合时,将抛出此 Hibernate 异常。

因此,请确保在注册自定义侦听器时,从注册表中删除相应的默认侦听器。

于 2018-01-18T17:59:35.773 回答
0

我的问题是我已经建立了@ManyToOne关系。也许如果上面的答案不能解决您的问题,您可能需要检查错误消息中提到的关系。

于 2020-05-20T08:49:21.847 回答
0

在这里发帖是因为我花了 2 多周的时间才弄清楚这个问题,但我没有完全解决它。

有一个机会,您也只是遇到了这个自 2017 年以来一直存在并且尚未得到解决的错误

老实说,我不知道如何解决这个错误。我在这里发帖是为了我的理智,希望能减少你在谷歌上搜索的时间。我喜欢任何人可能有的任何输入,但我对这个问题的特定“答案”未列在上述任何答案中。

于 2020-08-19T20:16:42.050 回答
-1

一对多多对一的关系中,将发生此错误。如果您尝试将多对一实体的相同实例用于一对多实体的多个实例。

例如,每个人可以拥有多本书,但如果您认为一本书的所有者不止一个,则每本书只能由一个人拥有,则会引发此问题。

于 2020-07-14T12:23:17.030 回答