当用户操作可以删除中间的行时,如何处理数据库分页?
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
,但我又对此感到有些困惑。剩余项目将始终依赖于 pageNo
和 perPage
而独立于 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)中的任何内容。
我陷入了困境。我希望我能在这里得到解决方案。我正在使用分页在用户个人资料页面上显示一些数据。
使用基本分页:
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
,但我又对此感到有些困惑。剩余项目将始终依赖于 pageNo
和 perPage
而独立于 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)中的任何内容。