一尘不染

从EJB计时器中删除大量行

sql

我需要从EJB Timer中从表中删除数百万行。问题在于计时器的事务超时时间为90秒,因此我应该将工作划分为几小块。

由于我不知道90秒钟内可以删除多少行,因此该算法应循环循环并一次删除几行,直到时间快用完为止。

问题是:如何在JPA中优雅地限制要删除的行数?删除是在时间戳早于特定日期的所有行上进行的。

我猜有可能找到第1000个最旧的行DELETE WHERE timestamp <= {1000th-oldest- row.timestamp},但是,这不是很优雅,我必须到达1000的最后一行才能获得时间戳。

其次,如果90秒后桌子不干净,计时器应立即再次触发。这很容易解决,但又不是很优雅。


阅读 141

收藏
2021-05-16

共1个答案

一尘不染

您拥有的解决方案仍然会面临交易到期问题。

诀窍是在一个单独的事务中执行每个块,如下面的伪代码所示。

@Entity

@NamedQueries ( value = {
    @NamedQuery (
        name = pagedDeleteExpiredItems
        query=    DELETE FROM MyTable
            WHERE (<table key>) IN (
                SELECT <table key> FROM (
                SELECT ROWNUM AS row_num, <table key> FROM MyTable
                WHERE timestamp <= :currentTime
                )
                WHERE row_num < :pageSize
            )
    )
})

public class MyEntity {
    @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
    int doPagedDeleteExpiredItems(Date currentTime, int pageSize) {
        Query query = em.createNamedQuery("pagedDeleteExpiredItems");
        query.setParameter("currentTime", currentTime);
        query.setParameter("pageSize", pageSize);
        int deleteCount = query.executeUpdate();
        return deleteCount;
    }
}


@EJBTimer
public class DeleteExpiredItemsTimer {

    @EJB(beanName = "MyEntity")
    MyEntity myEntity;

    @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
    void handleTimeout(Timer timer) {
        Date currentTime = getCurrentTime()
        int pageSize = 100
        int deleteCount;
        do {
            myEntity.doPagedDeleteExpiredItems(currentTime, pageSize);
        } while(deleteCount>0);
    }
}
2021-05-16