1

在 JPA 中,在执行诸如此类的批量操作时

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

建议使用单独的实体管理器以避免破坏同步,根据:UPDATE SET Queries in JPA/JPQL

例如,EntityManager 可能不知道其持久性上下文中的缓存实体对象已被 UPDATE 查询修改。因此,为 UPDATE 查询使用单独的 EntityManager 是一个很好的做法。

如何在 Wildfly 等 JTA 环境中使用 hibernate 创建单独的实体管理器?我是否需要为批量操作创建单独的持久性单元?

编辑:鉴于我不需要单独的 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:按照安德烈的建议,这应该可行:

@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;
        }
    }

    ...
}

测试确认拦截器被调用了两次。

4

1 回答 1

2

仅当您还对 进行其他操作时,该建议才有效EntityManager(当存在操作/读取与 BULK UPDATE 相同的实体的风险时)。最简单的解决方案:确保此 BULK UPDATE 在新事务中的单独服务中执行。无需为批量操作创建单独的 PU(持久性单元)。

于 2015-11-09T13:02:05.853 回答