![](/img/trans.png)
[英]Caused by: org.hibernate.HibernateException: Found shared references to a collection
[英]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
兩個person
並anotherPerson
必須相同。 也許您正在加載實體后重置該集合? 或者您已經使用相同的集合實例初始化了兩個引用?
我有同樣的問題。 就我而言,問題是有人使用 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)
。 這里的源和目標都使用相同的集合作為屬性。
所以我只是使用了如下的深拷貝..
我經歷過一個很好的例子來重現這樣的問題。 也許有一天我的經驗會對某人有所幫助。
檢查您的容器的 @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 檢查這個並拋出那個錯誤。 您可以執行以下操作:
例如:
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.