首頁 > 後端開發 > Golang > golang實現多層評論

golang實現多層評論

WBOY
發布: 2023-05-10 12:25:07
原創
907 人瀏覽過

隨著社群媒體和內容平台的興起,多層次評論系統成為了各類平台進行使用者互動和社群互動的重要方式。在前端實現多層評論系統相對來說比較簡單,但是後端實作起來卻相對複雜。本文將介紹如何使用golang實現多層評論。

實現想法

多層評論其實就是樹狀結構的展示,每個評論可以作為節點。可以使用樹狀結構的基本資料結構—樹和二元樹來實現多層評論系統。在本文中,我們選擇使用樹狀結構的二元樹來實現。

二元樹的節點由左右兩個子節點組成,左節點為目前節點的第一個子節點,右節點為目前節點的第二個子節點。因此,每次增加評論的時候,我們只需要關注當前評論的父節點以及它的左右子節點。

資料庫設計

為了實現多層評論系統,需要在資料庫中儲存每個評論的父子關係。一般情況下,我們可以使用兩種方式來儲存樹狀結構:

  1. 使用多表關聯
  2. 在單一表中使用自引用關係

#在本文中,我們選擇使用第二種方式,即在單表中使用自引用關係。

評論表(comment)的結構如下:

CREATE TABLE `comment` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `parent_id` int(11) DEFAULT NULL COMMENT '父级评论id',
  `content` varchar(255) DEFAULT NULL COMMENT '评论内容',
  `created_at` datetime DEFAULT NULL COMMENT '创建时间',
  PRIMARY KEY (`id`),
  KEY `parent_id` (`parent_id`),
  CONSTRAINT `comment_ibfk_1` FOREIGN KEY (`parent_id`) REFERENCES `comment` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='评论表'
登入後複製

在上述表格結構中,parent_id表示目前評論的父節點id,如果目前評論是一級評論,則parent_id為null。 id為目前評論的id,content為評論內容,created_at為建立時間。

程式碼實作

連結資料庫

首先,需要使用golang中的database/sql和mysql驅動來連結資料庫:

dsn := "root:123456@tcp(127.0.0.1:3306)/test"
db, err := sql.Open("mysql", dsn)
if err != nil {
   fmt.Printf("mysql connect error %s", err.Error())
   return
}
登入後複製

插入評論

插入評論時,需要判斷當前評論是作為父節點還是子節點來處理。

如果目前評論是作為父節點,直接插入資料庫中,如果目前評論是子節點,則需要更新父節點的右節點。

// 添加评论
func AddComment(comment Comment) error {
   if comment.ParentID == 0 {
       _, err := db.Exec("INSERT INTO comment(parent_id, content, created_at) VALUES(?, ?, ?)", nil, comment.Content, comment.CreatedAt)
       if err != nil {
           return err
       }
   } else {
       var rightNode *int
       err := db.QueryRow("SELECT right_node FROM comment WHERE id = ?", comment.ParentID).Scan(&rightNode)
       if err != nil {
           return err
       }
       tx, err := db.Begin()
       if err != nil {
           return err
       }
       // 更新右节点
       _, err = tx.Exec("UPDATE comment SET right_node = right_node + 2 WHERE right_node > ?", rightNode)
       if err != nil {
           tx.Rollback()
           return err
       }
       _, err = tx.Exec("UPDATE comment SET left_node = left_node + 2 WHERE left_node > ?", rightNode)
       if err != nil {
           tx.Rollback()
           return err
       }
       _, err = tx.Exec("INSERT INTO comment(parent_id, left_node, right_node, content, created_at) VALUES(?, ?, ?, ?, ?)", comment.ParentID, rightNode, rightNode+1, comment.Content, comment.CreatedAt)
       if err != nil {
           tx.Rollback()
           return err
       }
       tx.Commit()
   }
   return nil
}
登入後複製

查詢評論

查詢註解時,需要依照節點的左右順序進行排序,以取得到樹狀結構的註解清單。在查詢評論的時候,由於需要使用左右節點進行排序,所以需要將左右節點列加入查詢條件。此外,還需要使用一個level字段,表示當前節點是第幾個節點,方便前端展示。

type Comment struct {
   ID        int    `json:"id"`
   ParentID  int    `json:"parent_id"`
   Content   string `json:"content"`
   LeftNode  int    `json:"left_node"`
   RightNode int    `json:"right_node"`
   Level     int    `json:"level"`
   CreatedAt string `json:"created_at"`
}

// 获取评论列表
func GetComments() ([]Comment, error) {
   rows, err := db.Query("SELECT id, parent_id, content, created_at, left_node, right_node, (COUNT (parent.id) -1) AS level FROM comment AS node, comment AS parent WHERE node.left_node BETWEEN parent.left_node AND parent.right_node GROUP BY node.id ORDER BY left_node")
   if err != nil {
       return nil, err
   }
   defer rows.Close()

   var comments []Comment
   for rows.Next() {
       var comment Comment
       err := rows.Scan(&comment.ID, &comment.ParentID, &comment.Content, &comment.CreatedAt, &comment.LeftNode, &comment.RightNode, &comment.Level)
       if err != nil {
           return nil, err
       }
       comments = append(comments, comment)
   }
   return comments, nil
}
登入後複製

刪除註解

刪除註解的時候,需要判斷目前註解是父節點還是子節點,如果是父節點,需要刪除整個子樹。

// 删除评论
func DeleteComment(id int) error {
   tx, err := db.Begin()
   if err != nil {
       return err
   }
   var leftNode int
   var rightNode int
   err = tx.QueryRow("SELECT left_node, right_node FROM comment WHERE id = ?", id).Scan(&leftNode, &rightNode)
   if err != nil {
       tx.Rollback()
       return err
   }
   if leftNode == 1 && rightNode > 1 {
       // 删除子树
       _, err = tx.Exec("DELETE FROM comment WHERE left_node >= ? AND right_node <= ?;", leftNode, rightNode)
       if err != nil {
           tx.Rollback()
           return err
       }
       err = tx.Commit()
       if err != nil {
           tx.Rollback()
           return err
       }
   } else {
       // 删除单个节点
       _, err = tx.Exec("DELETE FROM comment WHERE id = ?", id)
       if err != nil {
           tx.Rollback()
           return err
       }
       err = tx.Commit()
       if err != nil {
           tx.Rollback()
           return err
       }
   }
   return nil
}
登入後複製

結語

透過上述程式碼實現,我們可以快速地建構出一個功能完整的多層評論系統。當然,這只是一個基礎的實現方式,在實際場景中,還需要根據具體的需求做出相應的最佳化和擴展。

以上是golang實現多層評論的詳細內容。更多資訊請關注PHP中文網其他相關文章!

來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板