从EJB Timer中删除大量行

时间:2010-02-17 14:10:56

标签: java sql jpa timer ejb

我需要从EJB Timer中删除表中的数百万行。 问题是计时器的事务超时为90秒,所以我应该将工作分成一口大小的块。

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

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

我想有可能找到第1000个最老的行和DELETE WHERE timestamp <= {1000th-oldest-row.timestamp}然而,这不是很优雅,我必须到达1000的最后一行来获取时间戳。

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

4 个答案:

答案 0 :(得分:2)

您仍将面临使用您的解决方案的交易过期问题。

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

@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);
    }
}

答案 1 :(得分:1)

我们有类似的要求,这就是我们如何解决它。我使用的是EJB 3.0。

  1. 计时器在应用程序启动时启动。服务器在ServletContextListener
  2. 中启动(或部署模块)
  3. 当计时器触发时,它最多可处理100行待处理的行。然后,您需要订购查询结果并限制行数。
  4. 如果有100行,则计时器会使用0ms计划下一次超时。它,事务已提交,计时器在新事务中再次触发。
  5. 如果行数少于100行,则计时器会在90sec中计划下一个超时。
  6. 如果有250行,则计时器按顺序触发三次。如果正好要处理100行,那么只有一个小问题,在这种情况下,计时器按顺序触发两次,但第二次触发实际上没有任何处理。但总而言之,它工作正常。

答案 2 :(得分:1)

我在SQL中使用的一个技巧是删除TOP 1000(或100或10000,取决于页面中的平均行数),如下所示:

DELETE top 1000 WHERE timestamp <= @ExpirationDate

重复调用此操作,直到没有删除任何行(使用@@ rowcount检查)或者您的时间不足。这种技术可以在JPA中实现吗?

答案 3 :(得分:0)

通过获取符合条件的行的排序列表并使用setFirstResult(int)与setMaxResults(int)相同来解决问题。通过这种方式,我可以从最旧的项目中获得大约maxCount步骤的项目顺序。

Query expired = dm.createNamedQuery("getExpiredElements");
expired.setParameter("currentTime", getCurrentTime());
expired.setMaxResults(maxCount);
expired.setFirstResult(maxCount);
@SuppressWarnings("unchecked")
List<Item> expiredChunk = (List<Item>) expired.getResultList();
long lastChunkEndTime = expiredChunk.get(0).getEndTime();
Query query = em.createNamedQuery("deleteExpiredItems");
query.setParameter("currentTime", lastChunkEndTime);
int result = query.executeUpdate();
return result >= maxCount;

如果应该再次执行该函数,则该函数返回true(至少)。