使用Hibernate在表中保留一定数量记录的最佳方法

时间:2018-02-13 12:41:15

标签: java database hibernate maintenance

我正在开发一个具有内置数据库维护功能的Hibernate / Spring应用程序。每隔15分钟,它会查看某些表,并根据某些参数清除旧记录。例如,在我的LogEntry实体的情况下,我基于2个参数进行清除:记录的年龄和表中的记录数。在第一种情况下,我正在做这样的事情:

@Override
public int deleteExpiredEntries(int systemLogKeepTimeInDays, int systemLogMaxEntries) 
{
    Session session = getSession();
    Query query = session.createQuery("DELETE FROM LogEntry l WHERE l.time < :p");

    Calendar cal = Calendar.getInstance();
    cal.setTime(new Date());
    cal.add(Calendar.DAY_OF_YEAR, -systemLogKeepTimeInDays);

    return query.setParameter("p", cal.getTime()).executeUpdate();
}

我正在尝试考虑使用类似过程运行此维护时始终保持5000条记录的最佳方法。我想过使用Id列并清除ID大于5000的任何内容,但这实际上会清除新记录而不是旧记录!

你会如何解决这个问题?

谢谢!

1 个答案:

答案 0 :(得分:0)

您可以尝试使用SQL查询本身来解决问题。

首先,你需要获得前5000个新记录。

SELECT id FROM LogEntry ORDER BY time DESC LIMIT 100000 OFFSET 5000;

我建议您使用LIMIT并根据需要进行设置,以便查询执行时间不会太长。通过这种方式,您可以尽可能多地执行查询,并且您将始终获取最新鲜的数据,因为ORDER BY和OFFSET 5000,您只保留了最新的5000条记录。

下一步将是删除:

DELETE FROM LogEntry WHERE id IN 
(SELECT id FROM ( SELECT id FROM LogEntry ORDER BY time DESC LIMIT 100000 OFFSET 5000) table_alias);

也许您想知道为什么我在子查询上使用SELECT。那是因为我需要引用我选择的结果,因为你看到它被命名为 table_alias 。 如果您尝试使用IN关键字使用子查询执行DELETE,则MySql本身将不会执行查询。你会收到错误:

This version of MySQL doesn't yet support 'LIMIT & IN/ALL/ANY/SOME subquery

官方文件(says):

  

通常,您无法修改表并从子查询中的同一个表中进行选择。

     

例外:前面的禁令不适用于   修改后的表您正在使用派生表(FROM中的子查询   这个派生表是物化的而不是合并的   外部查询。

MSSQL解决方案

DELETE FROM LogEntry WHERE id BETWEEN
(
SELECT MIN(id) FROM LogEntry ORDER BY time DESC 
OFFSET 5000 ROWS 
FETCH NEXT 100000 ROWS ONLY
)
AND
(SELECT MAX(id) FROM LogEntry ORDER BY time DESC 
OFFSET 5000 ROWS 
FETCH NEXT 100000 ROWS ONLY)

由于你在评论中要求使用MSSQL解决方案,我试图提出一些建议。我没有测试过这个查询,但是我有参考文件引导我:similar topic因为你需要忽略前5000行,请访问page

我希望这至少有一点帮助,甚至可以给你一个比我更好的想法,你能做什么!