Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/arduino/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java JPA许多ConcurrentModificationException问题_Java_Hibernate_Orm_Jpa - Fatal编程技术网

Java JPA许多ConcurrentModificationException问题

Java JPA许多ConcurrentModificationException问题,java,hibernate,orm,jpa,Java,Hibernate,Orm,Jpa,在ABC“层次结构”中,我们有三个具有双向多对多映射的实体,如下所示(当然是简化的): @实体 甲级{ @Id-int-Id; @可接合( name=“a_有b”, joinColumns={@JoinColumn(name=“a_id”,referencedColumnName=“id”)}, inverseJoinColumns={@JoinColumn(name=“b_id”,referencedColumnName=“id”)} @许多 收集垃圾; } @实体 B类{ @Id-int-I

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

@实体
甲级{
@Id-int-Id;
@可接合(
name=“a_有b”,
joinColumns={@JoinColumn(name=“a_id”,referencedColumnName=“id”)},
inverseJoinColumns={@JoinColumn(name=“b_id”,referencedColumnName=“id”)}
@许多
收集垃圾;
}
@实体
B类{
@Id-int-Id;
@可接合(
name=“b_有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)
私人收藏;
@ManyToMany(mappedBy=“bs”,fetch=FetchType.EAGER,
cascade={CascadeType.MERGE,CascadeType.PERSIST,CascadeType.REFRESH})
@org.hibernate.annotations.Fetch(FetchMode.SUBSELECT)
私人收藏;
}
@实体
C类{
@Id-int-Id;
@ManyToMany(mappedBy=“cs”,fetch=FetchType.EAGER,
cascade={CascadeType.MERGE,CascadeType.PERSIST,CascadeType.REFRESH})
@org.hibernate.annotations.Fetch(FetchMode.SUBSELECT)
私人收藏;
}
没有孤立的概念-从应用程序的角度来看,实体是“独立的”-大多数情况下,我们将有一把a:s,每个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 );
}
void removeA(A){
如果(a.getBs!=null){

就我所知,对于(B:a.getBs()){//这个问题与ORM无关。您不能使用Java中的语法sugar
foreach
构造从集合中删除元素。

请注意,
Iterator.remove
是在迭代过程中修改集合的唯一安全方法;如果在迭代过程中以任何其他方式修改了基础集合,则该行为未指定

问题代码的简化示例:


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

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
    }
}
void removeA(A)
{
如果(a!=null)
{
a、 setBs(new ArrayList());//清除a的所有Bs
entityManager.merge(a);//将状态与数据库同步
entityManager.remove(a);//现在应该可以在没有ConstraintViolationExceptions的情况下进行删除
}
}

Matt是正确的,但我想我应该添加一些关于解决此问题的其他方法的附加信息

问题在于A、B和C中的集合是神奇的Hibernate集合,因此当您运行以下语句时:

  b.getAs().remove( a );
这会从b的集合中删除a,但也会从a的列表中删除b,而a的列表恰好是在for循环中迭代的集合。这将生成
ConcurrentModificationException

如果你真的要删除集合中的所有元素,Matt的解决方案应该有效。但是如果你不这样做,另一个解决办法是将所有的b复制到一个集合中,从而从过程中删除神奇的Hibernate集合

    for ( B b : new ArrayList<B>( a.getBs() )) {
       b.getAs().remove( a ) ;
       entityManager.merge( b );
    }
for(B:newarraylist(a.getBs())){
b、 删除(a);
实体管理器合并(b);
}

这应该会让你走得更远。

格雷的解决方案奏效了!幸运的是,对于我们来说,JPA人员似乎一直在努力实现收藏,因为关于正确使用
列表
收藏的Sun官方文档表明:

请注意,Iterator.remove是在迭代过程中修改集合的唯一安全方法;如果在迭代过程中以任何其他方式修改了基础集合,则该行为未指定

我几乎对这个异常感到毛骨悚然,认为这意味着一个
@Stateless
方法无法从它自己的类调用另一个
@Stateless
方法。我觉得这很奇怪,因为我确信我在某个地方读到允许嵌套事务。所以当我搜索这个异常时,我发现了这个帖子并应用了Gray的解决方案。仅在我的例子中,我碰巧有两个独立的集合需要处理。正如Gray指出的,根据Java规范,从Java容器中删除成员的正确方法,您需要使用原始容器的副本进行迭代,然后执行
remove()
,这很有意义。否则,原始容器的链接列表算法会混淆

    for ( Participant p2 : new ArrayList<Participant>( p1.getFollowing() )) {
        p1.getFollowing().remove(p2);
        getEm().merge(p1);
        p2.getFollowers().remove(p1);
        getEm().merge(p2);
    }
for(参与者p2:newArrayList(p1.getFollowing())){
p1.getFollowing().remove(p2);
getEm().merge(p1);
p2.getFollowers().remove(p1);
getEm().merge(p2);
}

注意,我只复制了第一个集合(
p1.getFollowing()
),而不是第二个集合(
p2.getFollowers()
)。这是因为我只需要从一个集合中迭代,即使我需要从两个集合中删除关联。

谢谢你的回答。但我的情况真的是这样吗?我没有看到我在显式修改迭代的
集合,而是从其成员字段中删除内容(a
Collection
)。
EntityManager.merge(tt)
是否会影响提供
T
迭代器?@Gustav:EntityManager.merge(tt)
是否会影响
  b.getAs().remove( a );
    for ( B b : new ArrayList<B>( a.getBs() )) {
       b.getAs().remove( a ) ;
       entityManager.merge( b );
    }
    for ( Participant p2 : new ArrayList<Participant>( p1.getFollowing() )) {
        p1.getFollowing().remove(p2);
        getEm().merge(p1);
        p2.getFollowers().remove(p1);
        getEm().merge(p2);
    }