将表修剪为JPQL中的500条记录

adr*_*nus 5 java jpa jpql

我在某种缓存上工作,有时我们需要将表修剪为500条记录,基于a last_access_date(仅保留500条最近访问的行).

使用"普通"SQL,可以通过以下方式完成:

DELETE FROM records WHERE id not in 
    (SELECT id FROM records ORDER BY last_access_date DESC LIMIT 500)
Run Code Online (Sandbox Code Playgroud)

现在由于JPQL中没有LIMIT或类似的东西ROWNUM,我发现的唯一解决方案是在本机SQL中,这是次优的,因为我们运行在多个DBMS(至少Oracle和MSSQL)上.

此外,setMaxResults()(JPQL版本LIMIT)似乎对DELETE语句无效.

使用JPQL真的没办法吗?

Ayr*_*ton 3

你可以这样做:

String sql = "SELECT x.id FROM records x ORDER BY x.last_access_date DESC";
TypedQuery<Long> query = em.createQuery(sql, Long.class);

List<Long> ids = query.setMaxResults(500).getResultList();

String delete = "DELETE FROM records x where x.id not in :ids";
em.createQuery(delete).setParameter("ids", ids).executeUpdate();
Run Code Online (Sandbox Code Playgroud)

我不记得删除查询的确切语法,因此您可能必须在:ids括号之间添加括号,例如:

String delete = "DELETE FROM records x where x.id not in (:ids)";
Run Code Online (Sandbox Code Playgroud)

编辑: dkb在评论中提出了一个更快的解决方案(取决于唯一日期以确保剩余行数的完美准确性):

String sql = "SELECT x.last_access_date FROM records x ORDER BY x.last_access_date DESC";

//If you're not using calendar, change to your specific date class
TypedQuery<Calendar> query = em.createQuery(sql, Calendar.class);

Calendar lastDate = query.setFirstResult(499).setMaxResults(1).getSingleResult();

String delete = "DELETE FROM records x where x.last_access_date < :lastDate";
em.createQuery(delete).setParameter("lastDate", lastDate, TemporalType.DATE).executeUpdate();
Run Code Online (Sandbox Code Playgroud)