1

JPAでは、このような一括操作を行う場合

update LogEntry e set e.customer = null where e.customer.id = :cid

これによると、同期を壊さないように別のエンティティ マネージャーを使用することをお勧めします: JPA/JPQL での UPDATE SET クエリ

たとえば、EntityManager は、永続コンテキスト内のキャッシュされたエンティティ オブジェクトが UPDATE クエリによって変更されたことを認識していない場合があります。したがって、UPDATE クエリには別の EntityManager を使用することをお勧めします。

休止状態を使用して Wildfly などの JTA 環境で別のエンティティ マネージャーを作成するにはどうすればよいですか? 一括操作用に別の持続性ユニットを作成する必要がありますか?

編集:一括操作に別の PU が必要ない場合、これは新しいトランザクションを使用して解決するのに十分な方法ですか?

@Transactional
public class JpaCustomerRepository implements CustomerRepository {

    @Inject
    private EntityManager em;

    ...

    @Override
    public Customer remove(long id) {
        CustomerEntity entity = em.find(CustomerEntity.class, id);

        if (entity != null) {
            updateLogEntriesToNull(entity);

            em.remove(entity);
            return entity;
        } else {
            return null;
        }
    }

    @Transactional(value=TxType.REQUIRES_NEW)
    public void updateLogEntriesToNull(CustomerEntity entity) {
        em.createNamedQuery(LogEntry.updateCustomerToNull)
                .setParameter("cid", entity.getId())
                .executeUpdate();
    }

    ...
}

LogEntry.updateCustomerToNull一括クエリです。

回答:同じクラス内から呼び出されたときにインターセプターが呼び出されないため、これは機能しません。

EDIT2: Andreiからの提案に従って、これはうまくいくはずです:

@Transactional
public class JpaCustomerRepository implements CustomerRepository {

    public static class BulkUpdater {

        @Inject
        private EntityManager em;

        @Transactional(value=TxType.REQUIRES_NEW)
        public void updateLogEntriesToNull(CustomerEntity entity) {
            em.createNamedQuery(LogEntry.updateCustomerToNull)
                    .setParameter("cid", entity.getId())
                    .executeUpdate();
        }
    }

    @Inject
    private EntityManager em;

    @Inject
    private BulkUpdater bulkUpdater;

    ...

    @Override
    public Customer remove(long id) {
        CustomerEntity entity = em.find(CustomerEntity.class, id);

        if (entity != null) {
            bulkUpdater.updateLogEntriesToNull(entity);

            em.remove(entity);
            return entity;
        } else {
            return null;
        }
    }

    ...
}

テストでは、インターセプターが 2 回呼び出されることが確認されています。

4

1 に答える 1

2

EntityManager推奨事項は、 (BULK UPDATE と同じエンティティを操作/読み取るリスクがある場合) で他のことも行う場合にのみ有効です。最も簡単な解決策: この BULK UPDATE が新しいトランザクション内の別のサービスで実行されることを確認してください。一括操作用に個別の PU (持続性ユニット) を作成する必要はありません。

于 2015-11-09T13:02:05.853 に答える