gpt4 book ai didi

java - JPA ManyToMany ConcurrentModificationException 问题

转载 作者:行者123 更新时间:2023-12-02 08:28:07 25 4
gpt4 key购买 nike

我们在 A <-> B <-> C “层次结构”中拥有三个具有双向多对多映射的实体,如下所示(当然是简化的):

@Entity
Class A {
@Id int id;
@JoinTable(
name = "a_has_b",
joinColumns = {@JoinColumn(name = "a_id", referencedColumnName = "id")},
inverseJoinColumns = {@JoinColumn(name = "b_id", referencedColumnName = "id")})
@ManyToMany
Collection<B> bs;
}

@Entity
Class B {
@Id int id;
@JoinTable(
name = "b_has_c",
joinColumns = {@JoinColumn(name = "b_id", referencedColumnName = "id")},
inverseJoinColumns = {@JoinColumn(name = "c_id", referencedColumnName = "id")})
@ManyToMany(fetch=FetchType.EAGER,
cascade=CascadeType.MERGE,CascadeType.PERSIST,CascadeType.REFRESH})
@org.hibernate.annotations.Fetch(FetchMode.SUBSELECT)
private Collection<C> cs;
@ManyToMany(mappedBy = "bs", fetch=FetchType.EAGER,
cascade={CascadeType.MERGE,CascadeType.PERSIST, CascadeType.REFRESH})
@org.hibernate.annotations.Fetch(FetchMode.SUBSELECT)
private Collection<A> as;
}

@Entity
Class C {
@Id int id;
@ManyToMany(mappedBy = "cs", fetch=FetchType.EAGER,
cascade={CascadeType.MERGE,CascadeType.PERSIST, CascadeType.REFRESH})
@org.hibernate.annotations.Fetch(FetchMode.SUBSELECT)
private Collection<B> bs;
}

没有孤儿的概念 - 从应用程序的角度来看,实体是“独立的” - 大多数时候我们都会有一把 A:s,每个都有几个 B:s (有些可能在 A:s 之间“共享”,还有一些 1000 个 C:s,并非所有 B 都始终“使用”。我们得出的结论是,我们需要双向关系,因为每当实体实例删除后,所有链接(连接表中的条目)也必须删除。这样做是这样的:

void removeA( A a ) {
if ( a.getBs != null ) {
for ( B b : a.getBs() ) { //<--------- ConcurrentModificationException here
b.getAs().remove( a ) ;
entityManager.merge( b );
}
}
entityManager.remove( a );
}

如果集合(这里的a.getBs())包含多个元素,则会抛出ConcurrentModificationException。我已经绞尽脑汁有一段时间了,但想不出一种合理的方法来删除链接而不干扰集合,这让底层的迭代器很生气。

问题 1:考虑到当前的 ORM 设置,我应该如何执行此操作? (如果有的话……)

Q2:是否有更合理的方法来设计 OR 映射,让 JPA(在本例中由 Hibernate 提供)处理所有事情。如果我们不必包含那些我现在就会被删除,所以我认识的每个人,请仔细听:你不需要知道这个!-循环,就目前情况而言,无论如何都不起作用......

最佳答案

据我所知,这个问题与 ORM 无关。 您不能使用 Java 中的语法糖 foreach 构造从集合中删除元素。

Note that Iterator.remove is the only safe way to modify a collection during iteration; the behavior is unspecified if the underlying collection is modified in any other way while the iteration is in progress.

Source

有问题代码的简化示例:

List<B> bs = a.getBs();
for (B b : bs)
{
if (/* some condition */)
{
bs.remove(b); // throws ConcurrentModificationException
}
}

必须使用Iterator版本在迭代时删除元素。 正确实现:

List<B> bs = a.getBs();
for (Iterator<B> iter = bs.iterator(); iter.hasNext();)
{
B b = iter.next();
if (/* some condition */)
{
iter.remove(); // works correctly
}
}
<小时/>

编辑:我认为这会起作用;然而未经测试。如果没有,您应该停止看到 ConcurrentModificationException,但(我认为)您会看到 ConstraintViolationException

void removeA(A a)
{
if (a != null)
{
a.setBs(new ArrayList<B>()); // wipe out all of a's Bs
entityManager.merge(a); // synchronize the state with the database
entityManager.remove(a); // removing should now work without ConstraintViolationExceptions
}
}

关于java - JPA ManyToMany ConcurrentModificationException 问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4627221/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com