每个事务或批处理只触发一次JPA回调

时间:2015-02-20 16:27:31

标签: jpa eclipselink jpa-2.1

我按批次删除批次中的行(在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

1 个答案:

答案 0 :(得分:1)

不幸的是,JPA提供了实体回调,这些回调需要为他们监听的每个实体实例调用,因此您需要添加自己的功能,以确保每个批次/事务等只触发一次侦听器。替代方法是使用提供程序特定的行为,在这种情况下,EclipseLink的会话事件侦听器:https://wiki.eclipse.org/Introduction_to_EclipseLink_Sessions_(ELUG)#Session_Event_Manager_Events用于侦听PostCalculateUnitOfWorkChangeSet事件或在您需要时触发的其他事件。