Java 从EJB计时器中删除大量行
我需要在EJB计时器中从表中删除数百万行。 问题是计时器的事务超时时间为90秒,因此我应该将工作划分为小部分 因为我不知道90秒内可以删除多少行,所以算法应该循环并一次删除几行,直到时间快到为止 问题是: 如何在JPA中优雅地限制要删除的行数? 对时间戳早于某个日期的所有行进行删除Java 从EJB计时器中删除大量行,java,sql,jpa,timer,ejb,Java,Sql,Jpa,Timer,Ejb,我需要在EJB计时器中从表中删除数百万行。 问题是计时器的事务超时时间为90秒,因此我应该将工作划分为小部分 因为我不知道90秒内可以删除多少行,所以算法应该循环并一次删除几行,直到时间快到为止 问题是: 如何在JPA中优雅地限制要删除的行数? 对时间戳早于某个日期的所有行进行删除 我想可以找到最早的第1000行并删除timestamp中我们有类似要求的行,下面是我们如何解决它的。我使用的是EJB3.0 计时器在应用程序启动时启动。服务器启动或模块部署在ServletContextListene
我想可以找到最早的第1000行并删除timestamp中我们有类似要求的行,下面是我们如何解决它的。我使用的是EJB3.0 计时器在应用程序启动时启动。服务器启动或模块部署在ServletContextListener中。 当计时器启动时,它最多处理100行挂起的数据。然后需要对查询结果进行排序并限制行数。 如果有100行,计时器将下一次超时时间安排为0毫秒。当它启动时,事务被提交,计时器在新事务中再次触发。 如果少于100行,计时器将在90秒内安排下一次超时。
例如,如果有250行,计时器将按顺序触发三次。如果正好有100行要处理,则只有一个小问题,在这种情况下,计时器按顺序触发两次,但第二次触发实际上什么也不处理。但总而言之,它工作正常。我们有一个类似的需求,下面是我们如何解决它的。我使用的是EJB3.0 计时器在应用程序启动时启动。服务器启动或模块部署在ServletContextListener中。 当计时器启动时,它最多处理100行挂起的数据。然后需要对查询结果进行排序并限制行数。 如果有100行,计时器将下一次超时时间安排为0毫秒。当它启动时,事务被提交,计时器在新事务中再次触发。 如果少于100行,计时器将在90秒内安排下一次超时。
例如,如果有250行,计时器将按顺序触发三次。如果正好有100行要处理,则只有一个小问题,在这种情况下,计时器按顺序触发两次,但第二次触发实际上什么也不处理。但总而言之,它工作正常。我在SQL中使用的一个技巧是根据页面中的平均行数删除前1000行、前100行或前10000行,如下所示:
DELETE top 1000 WHERE timestamp <= @ExpirationDate
重复调用此函数,直到没有行被删除为止,请使用@rowcount进行检查,否则您的时间不足。这个技术可以在JPA中实现吗?我在SQL中使用的一个技巧是根据页面中的平均行数删除前1000行、前100行或前10000行,如下所示:
DELETE top 1000 WHERE timestamp <= @ExpirationDate
重复调用此函数,直到没有行被删除为止,请使用@rowcount进行检查,否则您的时间不足。这项技术可以在JPA中实现吗?通过获得符合清理条件的行的排序列表,并使用与SetMaxResultInt相同的setFirstResultint解决了这个问题。通过这种方式,我可以从最早的项目中获得大约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。通过获取符合清理条件的行的排序列表并使用与setMaxResultInt相同的setFirstResultint,解决了该问题。通过这种方式,我可以从最早的项目中获得大约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。您仍将面临现有解决方案的事务过期问题 诀窍是在单独的事务中执行每个块,如下面的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);
}
}
使用现有的解决方案,您仍将面临事务过期问题 诀窍是在单独的事务中执行每个块,如下面的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);
}
}
是的,这正是我想做的。但是我如何才能限制优雅地删除的行数呢?类似于按时间戳DESC limit 100从MyTable ORDER中删除。确切的SQL语法将取决于您使用的数据库。使用JDBC,您可以获得受删除影响的行数,并按照我所描述的进行操作。但是我如何才能限制优雅地删除的行数呢?类似于按时间戳DESC limit 100从MyTable ORDER中删除。确切的SQL语法将取决于您使用的数据库。使用JDBC,您可以获得受删除影响的行数,并按照我所描述的进行操作。但是你的解决方案很漂亮。好吧,交易在我的约束下为我解决了。但你的解决方案很漂亮。