【问题标题】:"Load more comments" button -> prevent loading duplicates due to changes in database“加载更多评论”按钮->防止由于数据库更改而加载重复项
【发布时间】:2017-10-21 00:45:20
【问题描述】:

我正在编写一个用户可以读写 cmets 的应用程序。

当cmets数量超过一定限制时,会显示“加载更多评论”按钮,并存储加载的cmets的偏移量。

每当用户写入或删除自己的 cmets 时,我都会更新此偏移量,这样就不会加载重复项,也不会遗漏任何 cmets。

但是我忘记了数据库因为其他用户添加/删除cmets而发生变化的情况。

所以offset方法似乎不可靠,那么有没有办法解决这个问题,也许是保存最后一条评论的id并将其用作某种“偏移量”?

我的查询中的 WHERE 子句如下:

WHERE x = ? ORDER BY y = ?(x 和 y 都不是 ID,y 不是唯一的)

【问题讨论】:

  • 添加时间戳列作为参考。
  • 我有一个索引时间戳列,但我该如何使用它?时间戳列本质上不是唯一的。

标签: mysql


【解决方案1】:

您可以使用时间戳列,甚至可能使用主键本身来执行此操作,具体取决于您的设置方式。如果主键是AUTO_INCREMENT 整数,这是一个使用主键的示例。

CREATE TABLE `comments` (
    `comment_id` int NOT NULL AUTO_INCREMENT,
    `thread_id` int NOT NULL, 
    `comment` text,
    PRIMARY KEY (`comment_id`),
    FOREIGN KEY (`thread_id`) REFERENCES `threads` (`thread_id`)
);

在该表定义中,您有一个 AUTO_INCREMENT int 主键。您还有一个thread_id,它是threads 表的外键。最后,您在comment 中有评论本身。

当您第一次为某个线程加载页面时,您需要执行以下操作:

SELECT comment_id, comment 
FROM comments 
WHERE thread_id = 123 
ORDER BY comment_id
LIMIT 10; 

这意味着您将为您的给定线程选择 10 个按 int PK 排序的 cmets(在本例中为 123)。现在,当您显示此内容时,您需要以某种方式保存最大的comment_id。在这种情况下说它是10。然后,让“加载更多 cmets”按钮在单击时将这个最大的 comment_id 传递给服务器。服务器现在将执行以下操作:

SELECT comment_id, comment
FROM comments
WHERE thread_id = 123 AND comment_id > 10 -- 10 is the value you passed in as your largest previously loaded comment_id
ORDER BY comment_id
LIMIT 10;

现在您有一组另外十个 cmets,您知道没有一个 cmets 可能与您之前显示的 cmets 重复,并且您永远不会跳过任何 cmets,因为它们总是按升序排列 int 键.

如果您现在回顾一下用于加载初始 cmets 集的查询,您会发现它与加载其他 cmets 的查询几乎相同,因此您实际上可以对两者使用相同的查询。当您最初加载 cmets 时,只需将 0 作为最大的 comment_id 传递。

如果您没有像这样工作的主键,您也可以使用timestamp 列执行相同的操作,并且您也不想将其更改为像这样工作。您只需按timestamp 列对结果进行排序,然后将最后加载的评论的timestamp 传递给您的“加载更多 cmets”函数。为了避免跳过同时发布的 cmets,您可以使用具有六位小数秒精度的 timestamp。将timestamp 列创建为TIMESTAMP(6)。然后,您的时间戳将被记录为2014-09-08 17:51:04.123456 之类的东西,其中第二个后的最后六位数字是一秒的小数。有了这么高的精度,您几乎不可能同时记录 cmet。

当然,您仍然可以在相同的确切时间戳记录两个或更多 cmets,但这不太可能。这使得 AUTO_INCREMENT int 成为一个更好的解决方案。最后一个选项是使用基于时间的UUID,因为它们包含一种机制,通过在同一微秒内发生事情时稍微调整值来确保唯一性。它们也仍然按时间排序。这样做的问题是 MySQL 对 UUID 的支持不是很好。

【讨论】:

  • 使用时间戳作为过滤器的问题是,两个或多个 cmets 可以具有相同的时间戳值。
  • 你可以通过使用更高分辨率的timestamp来处理这个问题。 MySQL 为您提供六位小数秒精度的时间戳:dev.mysql.com/doc/refman/5.7/en/fractional-seconds.html 更新我的答案以详细说明这一点。
  • 我猜由于数据库需要插入一行的时间,每个条目都有一个更高分辨率的时间戳?这会很棒。
  • 有没有特殊的方法来选择这种时间戳?当我使用 MySql 客户端查看我的表时,我看到了微秒,但是当我在 SELECT 语句中检索数据时,它类似于2017-05-21 12:28:43
  • 我不确定为什么会这样。你是如何插入timestamp 的?你在使用 MySQL now() 函数吗?如果是这样,那么你需要做now(6)。如果您在CREATE TABLE 语句中使用your_date timestamp(6) 创建表,然后使用now(6) 插入数据作为日期,那么当您执行select(*) 时,您将看到微秒。如果不是这种情况,请使用您的执行表创建 sql 和插入方式更新您的原始问题。
猜你喜欢
  • 2017-05-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多