내 항목을 업데이트 할 때 "ConcurrentModificationException"발생

Nov 06 2020

문제

최대 절전 모드 5.4.11 코어를 사용하고 있으며 많은 양의 엔티티를 업데이트하려고 할 때 바로 여기에서 해당 문제가 발생합니다. 최대 절전 모드 내부 예외처럼 보입니다.

최신 정보

최대 절전 모드 5.4.23으로 테스트했는데 동일한 예외가 발생했습니다. 또한 "mysql 커넥터"를 최신 버전 "8.0.22"로 업데이트했는데 동일한 예외가 발생했지만 작동하지 않았습니다.

설명

이것이 내가 엔티티를 업데이트하는 방법이며 다른 스레드에서 실행되며 여기서 문제가되지 않아야합니다 ... 기본적으로 데이터베이스 작업을위한 자체 스레드이며 다른 데이터베이스 작업이 실행되지 않습니다.

        // Run the database operation for updating the entities async in a new thread, return updated entities once done
        return CompletableFuture.runAsync(() -> {

            var session = database.openSession();
            session.beginTransaction();

            try {

                // Save identities first
                for (var identity : identities)
                    session.update(identity);

                // Update components, each component-type
                for(var insertedClass : insertationOrder)
                    for (var hbc : componentsPerType.get(insertedClass))
                        session.update(hbc);

                session.flush();
                session.clear();

                session.getTransaction().commit();
            } catch (Exception e){

                var messageComposer = new ExceptionMessageComposer(e);
                GameExtension.getInstance().trace("Update : "+messageComposer.toString());
                session.getTransaction().rollback();
            }

            session.close();
        }).thenApply(v -> entities);

내가 저장하려는 수업

@Entity
@Table(name = "chunk", uniqueConstraints = {@UniqueConstraint(columnNames={"x", "y"})}, indexes = {@Index(columnList = "x,y")})
@Access(value = AccessType.FIELD)
@SelectBeforeUpdate(false)
public class Chunk extends HibernateComponent{

    public int x;
    public int y;
    public Date createdOn;

    @OneToMany(fetch = FetchType.EAGER)
    @JoinTable(name = "chunk_identity", joinColumns = @JoinColumn(name = "identity_id"), inverseJoinColumns = @JoinColumn(name = "id"), inverseForeignKey = @ForeignKey(ConstraintMode.NO_CONSTRAINT))
    @Fetch(FetchMode.JOIN)
    @BatchSize(size = 50)
    public Set<Identity> inChunk = new LinkedHashSet<>();

    @Transient
    public Set<ChunkLoader> loadedBy = new LinkedHashSet<>();

    public Chunk() {}
    public Chunk(int x, int y, Date createdOn) {
        this.x = x;
        this.y = y;
        this.createdOn = createdOn;
    }
}



@Entity
@Table(name = "location")
@Access(AccessType.FIELD)
public class Transform extends HibernateComponent {

    @Embedded
    public Vector2 position = new Vector2();

    @ManyToOne
    @JoinColumn(name = "chunk_id", referencedColumnName = "identity_id", updatable = false)
    @Fetch(FetchMode.JOIN)
    public Chunk chunk;

    @Transient
    public Vector2 previousPos = new Vector2();

    public Transform() {}
    public Transform(Vector2 position) { this.position = position; }
    public Transform(Vector2 position, Chunk chunk) { this.position = position; this.chunk = chunk; }
}

내가 얻는 예외

19:29:05,126 INFO  [ForkJoinPool.commonPool-worker-19] Extensions     - {Game}: Update : java.util.ConcurrentModificationException:
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
Exception: java.util.ConcurrentModificationException
Message: *** Null ***
+--- --- ---+
Stack Trace:
+--- --- ---+
java.base/java.util.HashMap$HashIterator.nextNode(HashMap.java:1493) java.base/java.util.HashMap$KeyIterator.next(HashMap.java:1516)
org.hibernate.persister.collection.AbstractCollectionPersister.insertRows(AbstractCollectionPersister.java:1555)
org.hibernate.action.internal.CollectionUpdateAction.execute(CollectionUpdateAction.java:89)
org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:604)
org.hibernate.engine.spi.ActionQueue.lambda$executeActions$1(ActionQueue.java:478)
java.base/java.util.LinkedHashMap.forEach(LinkedHashMap.java:684)
org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:475)
org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:348)
org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:40)
org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:102)
org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1356)
org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1343)
com.parallelorigin.persistence.database.ECSDatabase.lambda$updateEntities$16(ECSDatabase.java:242)
java.base/java.util.concurrent.CompletableFuture$AsyncRun.run(CompletableFuture.java:1736) java.base/java.util.concurrent.CompletableFuture$AsyncRun.exec(CompletableFuture.java:1728)
java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:290)
java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1020)
java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1656)
java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1594)
java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:177)
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

최대 절전 모드에서 내부 예외가 발생하는 이유와이 문제를 해결하기 위해 무엇을 할 수 있는지 아는 사람이 있습니까?

답변

3 ChristianBeikov Nov 07 2020 at 10:43

당신은 목록을 변경하지 마십시오 entities, identities또는 components당신이 / 업데이 트를 계속 또 다른 쓰레드는 작업을하는 동안.

엔티티를 유지 / 업데이트하는 스레드 는 엔티티 객체를 소유 해야 합니다. 즉, 트랜잭션이 실행되는 동안 다른 스레드가 상태를 방해 할 수 없습니다. 트랜잭션이 완료된 후에 만 ​​개체를 ​​다시 사용할 수 있습니다.

응용 프로그램이 무엇을하는지 모르겠지만 주 스레드의 개체에 액세스해야하는 경우 플러시 작업을 위해 개체를 복사 할 수 있습니다. 이렇게하면 플러시를 수행하는 스레드가 개체를 올바르게 소유하고 안전하게 작업 할 수 있습니다.