我需要从EJB Timer中从表中删除数百万行。问题在于计时器的事务超时时间为90秒,因此我应该将工作划分为几小块。
由于我不知道90秒钟内可以删除多少行,因此该算法应循环循环并一次删除几行,直到时间快用完为止。
问题是:如何在JPA中优雅地限制要删除的行数?删除是在时间戳早于特定日期的所有行上进行的。
我猜有可能找到第1000个最旧的行DELETE WHERE timestamp <= {1000th-oldest- row.timestamp},但是,这不是很优雅,我必须到达1000的最后一行才能获得时间戳。
DELETE WHERE timestamp <= {1000th-oldest- row.timestamp}
其次,如果90秒后桌子不干净,计时器应立即再次触发。这很容易解决,但又不是很优雅。
您拥有的解决方案仍然会面临交易到期问题。
诀窍是在一个单独的事务中执行每个块,如下面的伪代码所示。
@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); } }