我按批次删除批次中的行(在EJB中)。
int i=0;
List<Category> list = // Sent by a client which is JSF in this case.
for(Category category:list) {
if(++i%49==0) {
i=0;
entityManager.flush();
}
entityManager.remove(entityManager.contains(category) ? category : entityManager.merge(category));
}
Category
是JPA实体。
有一个回调可以监听此删除事件。
@ApplicationScoped
public class CategoryListener {
@PostPersist
@PostUpdate
@PostRemove
public void onChange(Category category) {
//...
}
}
调用此回调方法的次数与删除的行数一样多。例如,如果删除10行,则此方法将被调用10次。
有没有办法在事务结束时只调用一次回调方法,即只要执行此代码的EJB方法返回或至少每批次,即entityManager.flush();
何时发生?在这种情况下,前者是首选。
其他信息:
我正在使用WebSockets进行一些实时更新,当在几个数据库表上执行此类CRUD操作时,将通知客户端。因此,删除批处理中的每一行 - 每次删除一行时,向所有关联客户端发送消息是毫无意义的。他们应该只在交易(或至少一批)结束时一次/一次通知。
以下JPA 2.1标准批量删除方法不起作用,因为它不直接对实体进行操作。这种方法都不会通过使用等效的JPQL来触发JPA回调。
CriteriaBuilder criteriaBuilder=entityManager.getCriteriaBuilder();
CriteriaDelete<Category> criteriaDelete = criteriaBuilder.createCriteriaDelete(Category.class);
Root<Category> root = criteriaDelete.from(entityManager.getMetamodel().entity(Category.class));
criteriaDelete.where(root.in(list));
entityManager.createQuery(criteriaDelete).executeUpdate();
我使用的是带有JPA 2.1的EclipseLink 2.5.2
答案 0 :(得分:1)
不幸的是,JPA提供了实体回调,这些回调需要为他们监听的每个实体实例调用,因此您需要添加自己的功能,以确保每个批次/事务等只触发一次侦听器。替代方法是使用提供程序特定的行为,在这种情况下,EclipseLink的会话事件侦听器:https://wiki.eclipse.org/Introduction_to_EclipseLink_Sessions_(ELUG)#Session_Event_Manager_Events用于侦听PostCalculateUnitOfWorkChangeSet事件或在您需要时触发的其他事件。