当用户操作可以删除中间的行时,如何处理数据库分页?

How to deal with database pagination when a row in between can be deleted by user action?

我陷入了困境。我希望我能在这里得到解决方案。我正在使用分页在用户个人资料页面上显示一些数据。

使用基本分页:

public Page list(Query query, int pageNo, int perPage) {

    int totalResults = query.list().size();

    int firstResult = (pageNo - 1) * perPage;
    query.setFirstResult(firstResult);
    query.setMaxResults(perPage);
    List resultList = query.list();
    return new Page(resultList, perPage, pageNo, totalResults);
}

页class构造函数:

public Page(List resultList, int pageSize, int page, int totalResults)   {
    this.resultList = resultList;
    this.pageSize = pageSize;
    this.page = page;
    this.totalResults = totalResults;
    this.totalPages = (totalResults - 1) / pageSize + 1;
}

现在,如果结果正常显示而中间没有任何删除,则可以正常工作。但是用户可以从他的操作列表中删除项目。

让我们看看情况。假设有 totalResults - 17、perPage - 6 和 totalPages - 3。

现在,他在第一页删除了 2 个项目,总共留下了 15 个结果,第二页中的行 ID 已从 7 变为 9(因为没有两个项目,总结果现在是 15 岁)。

希望情况清楚。现在不需要这种中间转移。

我曾考虑将其实现为 remainingItems,但我又对此感到有些困惑。剩余项目将始终依赖于 pageNoperPage 而独立于 totalResult (因为总结果在两者之间减少)。我也不能在这里使用最后 n 行,因为行数将再次减少,从而改变我想要的结果。

我也不想在方法中保留太多参数。例如 - 假设我在参数中传递 toSatrtWith id 并从那里获取 perPage 行数,我可能会得到想要的东西。但我想要一个更优雅的解决方案。

简短回答:记住 "where you left off" 而不是计算位置。

长答案:请参阅我的博客,了解为什么 "Pagination via LIMIT and OFFSET is evil":http://mysql.rjweb.org/doc.php/pagination。 (您正在执行 PHP 等同于使用 LIMIT 和 OFFSET,因此该博客适用。)

[Next] 的 url 将包括本页最后一项的 id,然后在构建下一页时使用 WHERE id > $id。 (或本页第一项的 id,然后是 WHERE id >= $id。当在两者之间插入一行时,这种细微的差别会产生轻微的影响。)在 SQL 中也有这个: ORDER BY id ASC LIMIT 10。它只会获取 10 行,无论是哪个页面。如果没有这个技巧,您将获取当前页面之前所有页面的所有行。

[上一页] 页面类似,但有一个标志说要倒退 (ORDER BY id DESC LIMIT 10)。

[First] 可能最好不指定 id;然后代码会说 "Oh, I should build the first page."

[Last] 可以包含 Last 或 id=-1 或其他任何标志 - 然后在 SQL.

中使用类似 ORDER BY id DESC LIMIT 10 的内容

如果没有这种技术,在当前页面之前删除或插入的行会导致列表被移动一个项目(向前或向后),因此,用户错过(坏?)一行或得到一个行重复(很烦人)。

我遇到了完全相同的问题。

我的解决方案是以相反的顺序处理每一页,即我从最后一页开始,然后是倒数第二页,一直到第一页。这样,即使我删除了第 N+1 页中的某些行,这也不会改变第 N 页(或 N-1、N-2、..、1)中的任何内容。