簡體   English   中英

找到對集合 org.hibernate.HibernateException 的共享引用

[英]Found shared references to a collection org.hibernate.HibernateException

我收到此錯誤消息:

錯誤:找到對集合的共享引用:Person.relatedPersons

當我嘗試執行addToRelatedPersons(anotherPerson)

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

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

我的域名:

Person {

 static hasMany = [relatedPersons:Person];

}

知道為什么會這樣嗎?

當您嘗試保留多個共享相同集合引用的實體實例(即集合標識與集合相等性相反)時,Hibernate 會顯示此錯誤。

請注意,這意味着同樣的集合,而不是集合元素-換言之relatedPersons兩個personanotherPerson必須相同。 也許您正在加載實體后重置該集合? 或者您已經使用相同的集合實例初始化了兩個引用?

我有同樣的問題。 就我而言,問題是有人使用 BeanUtils 將一個實體的屬性復制到另一個實體,因此我們最終有兩個實體引用同一個集合。

鑒於我花了一些時間調查這個問題,我會推薦以下清單:

  • 尋找諸如entity1.setCollection(entity2.getCollection())getCollection返回集合的內部引用之類的場景(如果 getCollection() 返回集合的新實例,則您無需擔心)。

  • 查看clone()是否已正確實現。

  • 查找BeanUtils.copyProperties(entity1, entity2)

實踐說明。 如果您嘗試保存對象,例如:

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);

在線閱讀此錯誤的原因也可能是休眠錯誤,作為它似乎有效的解決方法,它是放置:

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

就我而言,我是從其他類中復制和粘貼代碼,所以我沒有注意到 getter 代碼寫得不好:

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

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

所有參考文獻都是概念性的,但如果你看一下 get 說letrases

我也遇到了同樣的問題,有人使用了BeanUtils.copyProperties(source, target) 這里的源和目標都使用相同的集合作為屬性。

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

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

我經歷過一個很好的例子來重現這樣的問題。 也許有一天我的經驗會對某人有所幫助。

精簡版

檢查您的容器的 @Embedded Id 是否沒有可能的沖突。

長版

Hibernate 實例化集合包裝器時,它會在內部 Map 中通過 CollectionKey 搜索已經實例化的集合。

對於具有 @Embedded id 的實體,CollectionKey 包裝 EmbeddedComponentType 並使用 @Embedded Id 屬性進行相等性檢查和 hashCode 計算。

因此,如果您有兩個具有相同 @Embedded Id 的實體,Hibernate 將實例化並通過第一個鍵放置新集合,並為第二個鍵找到相同的集合。 因此,兩個具有相同 @Embedded Id 的實體將填充相同的集合。

例子

假設您有一組具有惰性貸款的 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 映射的附加屬性,但與其他實體 Branch 有關系。

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

可能會發生您沒有帳戶到早午餐關系 ID 數據庫的 FK,因此 Account.BRANCH 列可以具有分支表中未顯示的任何值。

根據@NotFound(action = NotFoundAction.IGNORE)如果相關表中不存在值,Hibernate 將為該屬性加載值。

如果兩個 Accounts 的 X 和 Y 列相同(這很好),但 BRANCH 不同並且沒有出現在 Branch 表中,hibernate 將為兩者加載null並且嵌入的 Ids 將相等。

因此,兩個 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。

考慮一個實體:

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

並考慮一個業務邏輯類:

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

這里 user 和foo.getUser()共享相同的引用。 但是保存這兩個引用會產生沖突。

正確的用法應該是:

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

這樣就避免了沖突。

我在我的應用程序中遇到了類似的異常。 在查看FlushEntityEventListener后,很明顯異常是在FlushEntityEventListener類中拋出的。

在 Hibernate 4.3.7 中, MSLocalSessionFactory bean 不再支持eventListeners屬性。 因此,必須從各個 Hibernate 會話 bean 中顯式獲取服務注冊表,然后設置所需的自定義事件偵聽器。

在添加自定義事件偵聽器的過程中,我們需要確保從相應的 Hibernate 會話中刪除相應的默認事件偵聽器。

如果未刪除默認事件偵聽器,則會出現針對同一事件注冊的兩個事件偵聽器的情況。 在這種情況下,在迭代這些偵聽器時,針對第一個偵聽器,會話中的任何集合都將被標記為已到達,而針對第二個偵聽器處理相同的集合時,將拋出此 Hibernate 異常。

因此,請確保在注冊自定義偵聽器時從注冊表中刪除相應的默認偵聽器。

我的問題是我設置了@ManyToOne關系。 也許如果上面的答案不能解決您的問題,您可能需要檢查錯誤消息中提到的關系。

在這里發帖是因為我花了 2 周多的時間才弄明白這個問題,我仍然沒有完全解決它。

您也有可能遇到這個自 2017 年以來一直存在且尚未解決的錯誤

老實說,我不知道如何解決這個錯誤。 我在這里發帖是為了我的理智,希望能減少你幾周的谷歌搜索。 我喜歡任何人可能有的任何輸入,但我對這個問題的特定“答案”未列在上述任何答案中。

我不得不替換以下集合初始化:

challenge.setGoals(memberChallenge.getGoals());

    challenge.setGoals(memberChallenge.getGoals()
                                      .stream()
                                      .map(dmo -> {
                                          final ChallengeGoal goal = new ChallengeGoalImpl();
                                          goal.setMemberChallenge(challenge);
                                          goal.setGoalDate(dmo.getGoalDate());
                                          goal.setGoalValue(dmo.getGoalValue());

                                          return goal;
                                      })
                                      .collect(Collectors.toList()));

我變了

@OneToMany( cascade= CascadeType.ALL)
    
@JoinColumn(
            name = "some_id",
            referencedColumnName = "some_id"
    )

to

@OneToMany(mappedBy = "some_id", cascade= CascadeType.ALL)

您正在使用指針(間接),所以有時您復制的是 memory 地址,而不是您想要的對象/集合。 Hibernate 檢查這個並拋出那個錯誤。 您可以執行以下操作:

  1. 不要復制對象/集合;
  2. 啟動一個新的空的;
  3. 制作一個 function 復制它的內容並調用它;

例如:

public Entity copyEntity(Entity e){
    Entity copy = new Entity();
    e.copy(name);
    e.setCollection2(null);
    e.setCollection3(copyCollection(e.getCollection3());
    return copy;
}

一對多多對一的關系中,會發生此錯誤。 如果您嘗試將多個實體的同一個實例分配給多個實體的多個實例。

例如,每個人可以擁有多本書,但如果您考慮一本書的多個所有者,則這些書中的每一本書只能由一個人擁有,這個問題就被提出了。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM