spring-data-jpa:发现对集合org.hibernate.HibernateException的共享引用。

huangapple go评论74阅读模式
英文:

spring-data-jpa : Found shared references to a collection org.hibernate.HibernateException

问题

我知道这个问题已经被问过和回答了很多次,而且也有一种解决方法,比如在以下链接中:

https://stackoverflow.com/q/1692871/3493829
http://www.java2s.com/Questions_And_Answers/JPA/Collection/HibernateException.htm

但是以上方法都对我没有起作用。

我正在使用 SpringBoot, JPA, Hibernate
并且有如下提供的映射。

我正在检索 Phone 列表,并使用 for 循环进行迭代。
在迭代 phone 列表时,我遇到了错误 Found shared references to a collection: Phone.person

org.hibernate.HibernateException: Found shared references to a collection: Phone.person
	at org.hibernate.engine.internal.Collections.processReachableCollection(Collections.java:188) ~[hibernate-core-5.4.10.Final.jar:5.4.10.Final]
	at org.hibernate.event.internal.FlushVisitor.processCollection(FlushVisitor.java:50) ~[hibernate-core-5.4.10.Final.jar:5.4.10.Final]
	at org.hibernate.event.internal.AbstractVisitor.processValue(AbstractVisitor.java:104) ~[hibernate-core-5.4.10.Final.jar:5.4.10.Final]
	at org.hibernate.event.internal.AbstractVisitor.processValue(AbstractVisitor.java:65) ~[hibernate-core-5.4.10.Final.jar:5.4.10.Final]
	at org.hibernate.event.internal.AbstractVisitor.processEntityPropertyValues(AbstractVisitor.java:59) ~[hibernate-core-5.4.10.Final.jar:5.4.10.Final]
	at org.hibernate.event.internal.DefaultFlushEntityEventListener.onFlushEntity(DefaultFlushEntityEventListener.java:182) ~[hibernate-core-5.4.10.Final.jar:5.4.10.Final]
	at org.hibernate.event.internal.AbstractFlushingEventListener.flushEntities(AbstractFlushingEventListener.java:232) ~[hibernate-core-5.4.10.Final.jar:5.4.10.Final]
	at org.hibernate.event.internal.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:92) ~[hibernate-core-5.4.10.Final.jar:5.4.10.Final]
	at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:39) ~[hibernate-core-5.4.10.Final.jar:5.4.10.Final]

Phone 实体的映射如下:

@Entity
@Table(name = "PHONETABLE")
@Data
public class Phone {

// 其他列映射

    @ManyToMany
    @JoinTable(name = "SomeTable", joinColumns = {
            @JoinColumn(name = "column1", referencedColumnName = "personColumn") }, inverseJoinColumns = {
                    @JoinColumn(name = "id", referencedColumnName = "id", unique = true) })
    @JsonIgnore
    private Set<Person> person;

}

我正在调用 findByIdMethod 方法从仓库中获取数据。
我已经使用 lombok 生成 getter 和 setter。

如果有人知道解决方法,那就太好了。
谢谢!

英文:

I know this question is asked and answered a number of times and also has a workaround

like in
https://stackoverflow.com/q/1692871/3493829
http://www.java2s.com/Questions_And_Answers/JPA/Collection/HibernateException.htm

but none of the above worked for me.

I am using SpringBoot, JPA, Hibernate
and have mapping as provided below.

I am retrieving the list of Phone and iterating over it using for loop.
I am getting the error Found shared references to a collection: Phone.person while iterating over phone list

org.hibernate.HibernateException: Found shared references to a collection: Phone.person
	at org.hibernate.engine.internal.Collections.processReachableCollection(Collections.java:188) ~[hibernate-core-5.4.10.Final.jar:5.4.10.Final]
	at org.hibernate.event.internal.FlushVisitor.processCollection(FlushVisitor.java:50) ~[hibernate-core-5.4.10.Final.jar:5.4.10.Final]
	at org.hibernate.event.internal.AbstractVisitor.processValue(AbstractVisitor.java:104) ~[hibernate-core-5.4.10.Final.jar:5.4.10.Final]
	at org.hibernate.event.internal.AbstractVisitor.processValue(AbstractVisitor.java:65) ~[hibernate-core-5.4.10.Final.jar:5.4.10.Final]
	at org.hibernate.event.internal.AbstractVisitor.processEntityPropertyValues(AbstractVisitor.java:59) ~[hibernate-core-5.4.10.Final.jar:5.4.10.Final]
	at org.hibernate.event.internal.DefaultFlushEntityEventListener.onFlushEntity(DefaultFlushEntityEventListener.java:182) ~[hibernate-core-5.4.10.Final.jar:5.4.10.Final]
	at org.hibernate.event.internal.AbstractFlushingEventListener.flushEntities(AbstractFlushingEventListener.java:232) ~[hibernate-core-5.4.10.Final.jar:5.4.10.Final]
	at org.hibernate.event.internal.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:92) ~[hibernate-core-5.4.10.Final.jar:5.4.10.Final]
	at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:39) ~[hibernate-core-5.4.10.Final.jar:5.4.10.Final]

Mapping to Phone entity

@Entity
@Table(name = &quot;PHONETABLE&quot;)
@Data
public class Phone{

// other column mapping

    @ManyToMany
	@JoinTable(name = &quot;SomeTable&quot;, joinColumns = {
			@JoinColumn(name = &quot;column1&quot;, referencedColumnName = &quot;personColumn&quot;) }, inverseJoinColumns = {
					@JoinColumn(name = &quot;id&quot;, referencedColumnName = &quot;id&quot;, unique = true) })
	@JsonIgnore
	private Set&lt;Person&gt; person;

}

I am calling the findByIdMethod to fetch the data from the repository.
I have used lombok for getters are setters.

If anyone knows the solution then it would be great.
Thanks;

答案1

得分: 3

看起来您有多个具有相同“person”实例的“Phone”实例。当您克隆或复制“Phone”,或者执行类似于phone1.setPerson(phone2.getPerson())的操作时,可能会发生这种情况。

Person实例相同是可以的,但Set本身不应相同。每个手机应该创建一个新的Set实例,该实例仅在实体内部使用。

您可以通过在构造函数中实例化集合或在声明后直接实例化集合,然后永不调用集合的setter方法来确保这一点,例如:

private Set<Person> person = new HashSet<Person>();

void addPerson(Person person) {
    this.person.add(person);
}

只使用addPerson方法,不要使用setPerson方法(您还可以添加类似的辅助方法来添加多个人员、删除人员等)。

您还可以在getPerson getter方法中返回集合的副本,而不是返回集合本身,以确保集合实例永远不会泄漏出去。

英文:

It appears that you have multiple Phone instances with the same Set instance for person. This can happen when you clone or copy a Phone, or do something like phone1.setPerson(phone2.getPerson()).

It's okay for the Persons to be the same, but not the Set itself. Each phone should create a new instance of a Set that is only used within the entity.

You can make sure of this, by instantiating collections in the constructor or directly after declaration and then never calling the setter for the collection, e.g.

private Set&lt;Person&gt; person = new HashSet&lt;Person&gt;();

void addPerson(Person person) {
    this.person.add(person);
}

and only use addPerson, never setPerson (you can add similar helper methods to add multiple persons, or remove a person, etc.).

You can also return a copy of the set instead of the set itself in the getPerson getter to be sure that the collection instance never leaks out.

huangapple
  • 本文由 发表于 2020年4月7日 17:54:13
  • 转载请务必保留本文链接:https://go.coder-hub.com/61077311.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定