多线程评论PHP?

7

我之前写了一个评论脚本,但它只是单线程的。我希望它能够多线程运行,但只是为了让用户回复评论,而不是回复评论的评论。因此,线程只会有两层。

目前,我在数据库中存储user_id对应的comment_id

我能想到的唯一实现多线程评论的方法是,在评论表中添加一个parent字段。但如果这样做,当我用PHP选择评论时,我将不得不针对每个评论执行另一个SELECT命令来选择评论的子级(如果有)。这似乎会给数据库带来很多负担。

肯定有更好的方法。有没有关于此的想法或教程?


不阅读上下文的情况下,该问题毫无意义,因为“多线程”和“注释”通常指的是其他事物。 - Davy8
4个回答

16

有三(四)个备选方案:

  1. 使用递归查询来根据父 ID 选择所有评论。这在许多数据库产品中都得到了支持,语法取决于数据库类型。请查看文档以获取更多信息(搜索“递归”)。

  2. 如果在每个子评论中存储文章 ID,则可以通过一次常规的选择查询来选择具有相同文章 ID 的所有评论。您可以使用父 ID 将评论正确地显示在页面上,放置在正确的父级评论下面:

    SELECT * FROM comments WHERE article_id = :article_id
    
  3. 如果你只需要两层评论,可以使用扩展的 where 来包含一级和二级评论:

  4. SELECT * FROM comments 
    WHERE parent_id = :article_id
    OR    parent_id IN (SELECT id FROM comments WHERE parent_id = :article_id)
    
    也可以使用union all来组合两个具有相同列的查询,但由于我假设所有数据都来自同一张表,所以可能没有必要这样做(请参见上面扩展的where子句):
    SELECT * FROM comments WHERE parent_id = :article_id
    UNION ALL
    SELECT * FROM comments WHERE parent_id IN 
        (SELECT id FROM comments WHERE parent_id = :article_id)
    

    就我个人而言,我会选择选项2,因为它简单(不需要奇怪的SQL结构),高效(只需1个查询)且灵活(支持任意层级的评论)。


请您能否提供一个 PHP 代码和结果集的实际示例...我已经反复阅读了您的答案数小时,但仍无法弄清如何编写代码...谢谢。 - jcobhams
@VyrenMedia 我猜你正在尝试实现第二个选项。我不会为你提供完整的实现指南,但也许这篇文章可以帮到你:http://blog.tcs.de/creating-trees-from-sql-queries-in-javascript/ 。如果你需要更多帮助,请发布一个新的SO问题。 - The Nail

2

只需要一个查询操作,你只需正确地将数据循环存储到数组中,然后循环遍历该数组并显示评论。


这不止是一个查询!这就是我如何解释我本来会做的,我正在寻找更好的方法。 - Sean H Jenkins
你在谈论使用另一个SELECT语句,而我给了你一个更好的方法。 - JanLikar
不,你的解决方案仍将使用多个SELECT。感谢回答。 - Sean H Jenkins
1
如果您为每个评论存储文章ID,则只需要一个SELECT语句,即:SELECT * FROM comment WHERE article_id = :article_id - The Nail
1
我的解决方案使用1个查询,不多于1个。 - JanLikar

2
这是一种常见的层次结构或树形数据的使用方式。我曾经在Stack Overflow上回答了一个广受欢迎的问题:最高效/优雅的将平面表解析为树形结构的方法是什么? 我还写了一个演示文稿,介绍了树形结构数据的替代方案:使用SQL和PHP处理层次数据的模型
我的演示中没有包含另一种解决方案,即Slashdot如何处理分级评论。他们使用像您一样的“parent”列,因此每个评论都引用它回复的评论。但是,他们还包括一个“root”列,以便每个评论知道它所属的帖子。给定帖子上很少有超过几百条评论,通常您希望从评论线程的顶部开始获取给定帖子的整个评论树。
SELECT * FROM comments WHERE root = 1234;

当您获取评论时,您可以编写PHP代码,根据parent列将其处理为数组的数组(这就是@JanL答案中所提到的)。我在另一个Stack Overflow问题的答案中发布了执行此操作的代码,Convert flat array to the multi-dimentional


我知道这是一个旧帖子,但我想知道你所描述的方法如果有成千上万条评论的帖子,该如何处理,显然你不会选择所有行,但如果你使用LIMIT,你将失去树形结构...是否有解决方法?...诚挚问候,J - jon
@jon,你可以使用LIMIT,但按评论日期排序。 这样,您将获得最早的评论线程。 然后,如果用户想要扩展线程,他们可以请求它,但默认情况下,他们只能看到讨论的子集。 如果您想要更多详细信息,请下载Slashdot源代码并查看它们是如何实现的。http://slashcode.com/ - Bill Karwin
感谢您的回复,但是如果我理解正确的话,这只会显示原始评论线程,然后如果他们想要展开评论线程以查看任何回复,那么您将在该评论线程上执行选择,但是我真的希望在第一个查询中也能显示评论线程的回复,但同时也能够限制数量?使用相邻层次结构是否可能实现这一点?再次感谢J。 - jon
@jon,如果你使用MySQL并且想支持任意深度的评论回复线程,则无法在一个查询中使用邻接层次结构实现。这就是为什么人们提出了存储分层数据的替代方法(请参阅我链接的演示文稿)。其他数据库支持使用公共表达式的递归查询,因此可能是可能的。 - Bill Karwin
谢谢您一直以来的帮助...我已经阅读了您上面链接的文章,就我所理解的(我还在学习!),虽然这些存储层次数据的方法非常聪明,但邻接方法似乎是存储像评论和回复这样的内容的最佳方法...因为其他技术在用户发布回复时需要进行非常复杂的更新。我还仔细研究了Facebook和YouTube的评论............. - jon
看起来YouTube不会以树形格式显示对评论的回复,而Facebook只允许回复到一定深度...我猜如果他们无法在多层树形显示中显示评论回复,那么可能是不需要的...我想这部分原因是由于上述问题...再次感谢您的帮助Bill..问候J - jon

1

这个查询可能适用于您(我不知道您的结构,所以我猜测了一下):

SELECT * FROM comments a
LEFT JOIN comments b ON a.comment_id = b.parent_coment_id
LEFT JOIN comments c ON b.comment_id = c.parent_coment_id
WHERE a.comment_id <> b.comment_id
      AND a.comment_id <> c.comment_id
      AND b.comment_id <> c.comment_id;

这似乎没问题。我猜第二个LEFT JOIN和第二个AND是用于连接第三级评论的? - Sean H Jenkins
请注意,此方法仅适用于最多三级评论,并且不会过滤实际文章,我认为这可能很有用。 - The Nail
嗯,这会将其附加到末尾。我更希望有一种选择它们但将它们作为单独行的方法。 - Sean H Jenkins
那么你需要使用UNION而不是JOIN(或递归查询)。 - The Nail

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接