小编典典

使用JPA(Hibernate)查找包含给定记录的页面

hibernate

我如何知道记录在JPA查询中的位置?

我有一项返回分页结果的服务,该结果或多或少实现了带有此签名的方法:

List<Record> getRecordsPage(long page, int pageSize);

调用此命令时,我只是创建一个查询并按以下方式进行配置:

TypedQuery<Record> query = entityManager.createQuery(criteriaQuery);
query.setFirstResult(page * pageSize);
query.setMaxResults(pageSize);

这将分页结果。这可以按预期工作,并且非常简单。

问题

我的另一个要求是实现一种方法,该方法将检索包含特定记录的页面。实现具有以下签名的方法:

List<Record> getRecordsPage(Record record, int pageSize);

此方法需要得到记录所在的正确页面。例如,对于getRecordsPage(RECORD4, 2)调用,考虑数据库状态:

1. RECORD1 
2. RECORD2 
3. RECORD3 
4. RECORD4 
5. RECORD5

返回的页面应为2个,其中包含[RECORD3, RECORD4]

ORDER BY参数始终被设置,并且可以是多个字段。

直到现在的解决方案

到目前为止,我有一些解决方案是:

  1. 一点都不好,但是可以解决问题:

使用提供的查询,我只选择id而不进行分页,然后仅执行a
indexOf来查找其位置,然后基于该位置我可以找到记录所在的页面,然后使用getRecordsPage(long page, int pageSize)已实现的规则执行常规过程。

  1. 不太好,因为数据库很高:

在使用mySQL时,我可以执行类似:的sql select r from (select rownum r, id from t order by x,y) z where z.id = :id,它将返回记录的位置,并且可以使用它来调用getRecordsPage(long page, int pageSize)

好的解决方案

要求:

  1. 支持多个领域的订单;
  2. 给定查询,它将返回记录位置或包含记录的页面偏移量;

一个好的解决方案是:

  1. 纯粹是JPA;
  2. 好的 ,如果在数据库中执行一个额外的查询,只是找出记录位置;
  3. 好的 ,如果hibernate是在某一时刻使用(如Hibernate是背后JPA在这种情况下)。

阅读 318

收藏
2020-06-20

共1个答案

小编典典

确保我理解正确:您正在显示,Record并且想要显示所有记录的分页列表,从而预选了包含您的项目的页面?

首先,您必须知道关系数据库不提供数据库中记录的任何隐式排序。尽管它们似乎是从头到尾添加的,但它并不便携且可靠。

因此,您的分页列表/网格必须按某些列进行显式排序。为简单起见,假设您的网格按排序id。您知道当前显示的记录的ID(例如:)X。首先,您需要根据此排序顺序找出记录在表中的哪个位置:

SELECT COUNT(r)
FROM Record r
WHERE r.id < :X

该查询将返回记录 之前 的记录数。现在很简单:

int page = count / pageSize

page 基于0。

不幸的是,如果您的排序列不是唯一的,则可能无法在所有情况下都起作用。但是,如果该列不是唯一的,则排序本身就不稳定(具有相同值的记录可能会以随机顺序出现),因此请考虑按额外的唯一列进行排序:

...
ORDER BY r.sex, r.id

在这种情况下,记录首先按sex(很多重复项)和ID 排序。在当前记录之前对记录进行计数的解决方案仍然有效。

2020-06-20