Jpa 如何为JTA环境中的批量操作创建单独的实体管理器?

Jpa 如何为JTA环境中的批量操作创建单独的实体管理器?,jpa,wildfly,jta,bulkupdate,Jpa,Wildfly,Jta,Bulkupdate,在JPA中,当执行这样的批量操作时 update LogEntry e set e.customer = null where e.customer.id = :cid 建议使用单独的实体管理器,以避免中断同步,如下所示: 例如,EntityManager可能不知道其持久性上下文中的缓存实体对象已被更新查询修改。因此,使用单独的EntityManager进行更新查询是一种很好的做法 如何使用hibernate在JTA环境(如Wildfly)中创建单独的实体管理器?我是否需要为批量操作创建单独的

在JPA中,当执行这样的批量操作时

update LogEntry e set e.customer = null where e.customer.id = :cid
建议使用单独的实体管理器,以避免中断同步,如下所示:

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

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

编辑:鉴于批量操作不需要单独的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;
        }
    }

    ...
}

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

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

请参阅原始帖子中的后续问题。不,如果在
实例中的方法上调用@Transactional interceptor,则@Transactional interceptor将不起作用。但是您可以将其公开,在您的
JpaCustomerRepository
服务中注入另一个
@EJB私有JpaCustomerRepository injectedService实例,然后调用
injectedService.UpdateLogentriesToull(…)