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

Posted

技术标签:

【中文标题】使用 Hibernate 在表中仅保留一定数量记录的最佳方法【英文标题】:Best way to keep only a certain number of records in a table with Hibernate 【发布时间】:2018-02-13 12:41:15 【问题描述】:

我正在开发一个具有内置数据库维护功能的 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】:

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

首先,您需要获得前 5000 条新记录。

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

我建议您使用 LIMIT 并将其设置为适合您的需要,这样查询就不会花费太长时间来执行。这样,您可以尽可能多地执行查询,并且您将始终获取最新数据,因为 ORDER BY 和因为 OF​​FSET 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)

由于您要求在 cmets 中提供 MSSQL 解决方案,因此我试图提出一些建议。我还没有测试过这个查询,但是我有引用它:这个similar topic 并且因为你需要忽略前 5000 行,所以访问这个page

我希望这至少对您有所帮助,甚至让您比我更好地了解您可以做什么!

【讨论】:

您将如何翻译此查询以使用 MSSQL? 我会尽快找出答案,并用 MSSQL 解决方案更新答案。

以上是关于使用 Hibernate 在表中仅保留一定数量记录的最佳方法的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Oracle SQL 中仅选择最近 30 天内第一次在表中显示的这些 ID?

使用@ElementCollection 时出错:org.hibernate.MappingException:无法确定类型:java.util.Set,在表中:列

为什么使用JqGrid在表中不改变页面?

如何使用 Java 在 MySQL 表中仅搜索一条特定记录

如何从左表中仅获取一条记录与右表中的每条记录

如何在结果表中仅显示选定的记录