And*_*w H 7 java pagination hibernate cursor
有没有办法在 Web 请求之间使用 Hibernate 维护数据库游标?基本上,我正在尝试实现分页,但是被分页的数据一直在变化(即新记录被添加到数据库中)。我们正在尝试将其设置为当您进行初始搜索(最多返回 5000 个结果)并翻阅结果时,这些相同的记录总是出现在同一页面上(即我们不会连续运行查询每次单击下一页和上一页按钮时)。我们目前实现这一点的方法是仅从我们正在分页的表中选择 5000 个(最多)主键,将这些键存储在内存中,然后一次只使用 20 个主键从数据库中获取它们的详细信息. 然而,
我尝试使用 Hibernate 的 ScrollableResults 执行此操作,但发现我无法调用 next() 和 previous() 等方法,如果您在不同的 Web 请求/Hibernate 会话中会导致异常(这并不奇怪)。有什么方法可以将 ScrollableResults 对象重新附加到会话,就像重新附加分离的数据库对象以使其持久一样?是否有其他方法可以在不缓存主键的情况下实现具有一致分页结果的数据分页?
千万不要使用offset,因为offset也会读取offset之前的所有数据,效率很低。
您需要按索引的唯一属性进行排序,并在 API 调用中返回最后一项属性的值,并使用WHERE子句从您离开的位置开始。最后一项的属性值将是您的光标位置。例如,使用主键id作为游标的简单分页查询如下所示:
List<MyEntity> entities = entityManager
.createQuery("""
FROM
MyEntity e
WHERE
e.id > :cursorPosition
ORDER BY
e.id ASC
""", MyEntity.class)
.setParameter("cursorPosition", cursorPosition)
.setMaxResults(pageSize)
.getResultList()
Run Code Online (Sandbox Code Playgroud)
第一次调用 API,该cursorPosition值可以为 0。第二次您将从客户端收到客户端从第一次调用中收到的游标。了解Google Maps 分页地点查询如何使用该nextPageToken属性。
您的游标必须是一个字符串,用于标识您的查询的所有参数。因此,如果您有其他参数,则必须可以使用光标进行检索。
我相信你可以通过多种方式做到这一点。一种方法是将所有参数连接cursorPosition到一个字符串中,将其编码为像 Base64 这样的 URL 友好字符串,并在接收回解码时将其解码并将字符串拆分为原始参数:
String nextPageToken = Base64.getUrlEncoder()
.encodeToString("indexProperty=id&cursorPos=123&ageBiggerThan=65".getBytes())
Run Code Online (Sandbox Code Playgroud)
您的 api 调用将返回一个像这样的 json:
{
"items": [ ... ],
"nextPageToken": "aW5kZXhQcm9wZXJ0eT1pZCZjdXJzb3JQb3M9MTIzJmFnZUJpZ2dlclRoYW49NjU="
}
Run Code Online (Sandbox Code Playgroud)
客户端下一次调用:
GET https://www.example.com/api/myservice/v1/myentity?pageToken=aW5kZXhQcm9wZXJ0eT1pZCZjdXJzb3JQb3M9MTIzJmFnZUJpZ2dlclRoYW49NjU=
Run Code Online (Sandbox Code Playgroud)
连接和拆分游标字符串的部分可能很烦人,我真的不知道是否有一个库可以处理创建标记和解析它的这项工作,我实际上是在这个问题中,因为我正在寻找它。但我的猜测是 GSON 或 Jackson 可以为您节省这方面的代码行。
本质上来说,这件事你得靠你自己。您想要做的是查看 OpenSessionInView 过滤器并构建您自己的过滤器,这样您就可以从与用户 Web 会话关联的缓存中提取一个,而不是为每个请求创建一个新的 HibernateSession。
如果您没有像 Spring WebFlow 这样的框架来为您提供一些对话结构,那么您也需要构建它。因为除了“Web 会话过期”之外,您可能还需要某种方式来管理 Hibernate 会话的生命周期。您也很可能不希望来自同一 Web 会话的两个用户线程但不同的浏览器选项卡共享一个休眠会话。(很可能会随之而来。)