如何在 JTA 环境中为批量操作创建单独的实体管理器?
How do I create a separate entity manager for bulk operations in a JTA environment?
在 JPA 中,当进行像这样的批量操作时
update LogEntry e set e.customer = null where e.customer.id = :cid
建议使用单独的实体管理器以避免破坏同步,据此:UPDATE SET Queries in JPA/JPQL
For example, the EntityManager may not be aware that a cached entity object in its persistence context has been modified by an UPDATE query. Therefore, it is a good practice to use a separate EntityManager for UPDATE queries.
如何使用休眠在 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是批量查询。
回答: 这不起作用,因为从同一个 class.
内部调用时不会调用拦截器
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
执行其他操作时(当存在 manipulating/reading 与 BULK UPDATE 相同实体的风险时),该建议才有效。最简单的解决方案:确保此 BULK UPDATE 在新事务中的单独服务中执行。无需为批量操作创建单独的 PU(持久性单元)。
在 JPA 中,当进行像这样的批量操作时
update LogEntry e set e.customer = null where e.customer.id = :cid
建议使用单独的实体管理器以避免破坏同步,据此:UPDATE SET Queries in JPA/JPQL
For example, the EntityManager may not be aware that a cached entity object in its persistence context has been modified by an UPDATE query. Therefore, it is a good practice to use a separate EntityManager for UPDATE queries.
如何使用休眠在 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是批量查询。
回答: 这不起作用,因为从同一个 class.
内部调用时不会调用拦截器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
执行其他操作时(当存在 manipulating/reading 与 BULK UPDATE 相同实体的风险时),该建议才有效。最简单的解决方案:确保此 BULK UPDATE 在新事务中的单独服务中执行。无需为批量操作创建单独的 PU(持久性单元)。