我有一项返回分页结果的服务,该结果或多或少实现了带有此签名的方法:
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)调用,考虑数据库状态:
getRecordsPage(RECORD4, 2)
1. RECORD1 2. RECORD2 3. RECORD3 4. RECORD4 5. RECORD5
返回的页面应为2个,其中包含[RECORD3, RECORD4]。
[RECORD3, RECORD4]
该ORDER BY参数始终被设置,并且可以是多个字段。
ORDER BY
到目前为止,我有一些解决方案是:
使用提供的查询,我只选择id而不进行分页,然后仅执行a indexOf来查找其位置,然后基于该位置我可以找到记录所在的页面,然后使用getRecordsPage(long page, int pageSize)已实现的规则执行常规过程。
indexOf
getRecordsPage(long page, int pageSize)
在使用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)。
select r from (select rownum r, id from t order by x,y) z where z.id = :id
要求:
一个好的解决方案是:
确保我理解正确:您正在显示,Record并且想要显示所有记录的分页列表,从而预选了包含您的项目的页面?
Record
首先,您必须知道关系数据库不提供数据库中记录的任何隐式排序。尽管它们似乎是从头到尾添加的,但它并不便携且可靠。
因此,您的分页列表/网格必须按某些列进行显式排序。为简单起见,假设您的网格按排序id。您知道当前显示的记录的ID(例如:)X。首先,您需要根据此排序顺序找出记录在表中的哪个位置:
id
X
SELECT COUNT(r) FROM Record r WHERE r.id < :X
该查询将返回记录 之前 的记录数。现在很简单:
int page = count / pageSize
page 基于0。
page
不幸的是,如果您的排序列不是唯一的,则可能无法在所有情况下都起作用。但是,如果该列不是唯一的,则排序本身就不稳定(具有相同值的记录可能会以随机顺序出现),因此请考虑按额外的唯一列进行排序:
... ORDER BY r.sex, r.id
在这种情况下,记录首先按sex(很多重复项)和ID 排序。在当前记录之前对记录进行计数的解决方案仍然有效。
sex