Database design and implementation of comment system

Keywords: Database Java SQL Lombok

requirement analysis

Generally, when we browse the website, we can often see the effect as shown in the figure below (the picture comes from CSDN)

This kind of comment is nested layer by layer, and there are several replies to the comment under each comment.

This kind of structure is similar to the tree structure. Users can see it at a glance, and it is also a very mainstream design of comment system.

Database design

In the tree structure dominated by comments, the design of the database is very flexible, which can be a single table design. Each comment has a parent [ID] pointing to the parent comment. It can also be divided into two tables, one for comments and the other for comments.

Here I use a single table design.

The data table is designed as follows. Because I developed a news system, I took the project as an example.

Table fields Field description
commentId The id of the comment, self increment. Each comment corresponds to a unique commentId
newsId The id of the news corresponding to the comment
content Content of comments
userId The id of the user who sent the comment
parentId The id of the parent comment. If it is not a reply to the comment, the value is null
date Comment date

SQL statement:

Comments:

create table if not exists comments
(
    commentId bigint auto_increment primary key,
    newsId    bigint not null,
    parentId  bigint,
    content   text   not null,
    userId    bigint not null,
    date      timestamp default current_timestamp(),
    foreign key (parentID) references comments (commentId),
    foreign key (userID) references users (userId),
    foreign key (newsID) references news (newsId)
) charset = utf8mb4;

Realization

  • Query statement:
SELECT a.commentId,a.newsId,a.parentId,a.newsId,b.nickname,b.avatar,a.content,a.date
        FROM comments AS a,users AS b WHERE a.newsId=#{newsId} AND a.userId=b.userId

In order to reduce the number of database queries, all comments under a news are queried directly, and then the display structure of the comments is programmed. It is also one of the common optimization methods to improve performance through appropriate redundancy

  • Comment entity class

import lombok.Data;
import java.util.Date;
import java.util.List;

@Data
public class Comment {
    Long commentId;
    Long newsId;
    Long parentId;
    Long userId;
    String nickname;
    String avatar;
    String content;
    Date date;
    List<Comment> child;
}

Here is a piece of code to organize all comments through the program (for the sake of the simplification of the article, only write the logic related code)

public List<Comment> getComments(Long newsId) {
        List<Comment> allComments = commentMapper.getComments(newsId);
        if (allComments == null || allComments.size() == 0) {
            return new ArrayList<>();
        }
        List<Comment> comments = new ArrayList<>();
        List<Comment> parents = new ArrayList<>();
        for (Comment comment : allComments) {
            if (comment.getParentId()==null) {
                comments.add(comment);
                parents.add(comment);
            } else {
                boolean foundParent=false;
                for (Comment parent : parents) {
                    if (comment.getParentId() == parent.getCommentId()) {
                        if (parent.getChild() == null) {
                            parent.setChild(new ArrayList<>());
                        }
                        parent.getChild().add(comment);
                        parents.add(comment);
                        foundParent=true;
                        //If the list is modified at the same time during the list iteration, an exception of java.util.ConcurrentModificationException will be reported, so we need to break. Of course, break can also improve the algorithm efficiency
                        break;
                    }
                }
                if (!foundParent) {
                    throw new RuntimeException("can not find the parent comment");
                }
            }
        }
        return comments;

The above algorithm has two disadvantages:

  • High time complexity: O (n^2)
  • Depends on the premise that all comments in the allComments array are in ascending time order.

In fact, this is a typical flat data tree problem, and we can further optimize it to the best O (n) complexity

public List<Comment> getComments(Long newsId) {
        List<Comment> all = new ArrayList<>();
        Map<Long, Comment> map = new HashMap<>();
        List<Comment> result = new ArrayList<>();
        for (Comment c : all) {
            if (c.parentId == null) {
                result.add(c);
            }
            map.put(c.commentId, c);
        }
        for (Comment c : all) {
            if (c.parentId != null) {
                Comment parent = map.get(c.parentId);
                if (parent.child == null) {
                    parent.child = new ArrayList<>();
                }
                parent.child.add(c);
            }
        }
        return result;
    }

The final rendering.

The data returned by the interface is as follows:

{
    "code": "success",
    "message": "Get comment successful",
    "status": "200",
    "data": [
        {
            "id": "236051",
            "author_name": "Jianbo",
            "author_url": "https://wx.qlogo.cn/mmopen/vi_32/Qib5jkFMntPJnT8b2nyzKicoYSuXLeyl07ia1dianxx1fWcic9hJL4UOEuIJvoWWbx7IFia3olUGqiabZvTe0dmeFBicHQ/132",
            "date": "6 Hours ago",
            "content": "tt",
            "userid": "24",
            "child": []
        },
        {
            "id": "236028",
            "author_name": "Set sail",
            "author_url": "https://wx.qlogo.cn/mmopen/vi_32/7Aq39lKL2jxoWSMgbiaYkQzOR0mOMTm2TLjVhRicYaFXAzg20I8gpcqySYYYQMWG60p8r5kibG3ibiav3CC8Bzibjblw/132",
            "date": "2019-04-11",
            "content": "It's very simple and touching",
            "formId": null,
            "userid": "9676",
            "child": [
                {
                    "id": "236032",
                    "author_name": "Jianbo",
                    "author_url": "https://wx.qlogo.cn/mmopen/vi_32/Qib5jkFMntPJnT8b2nyzKicoYSuXLeyl07ia1dianxx1fWcic9hJL4UOEuIJvoWWbx7IFia3olUGqiabZvTe0dmeFBicHQ/132",
                    "date": "2 Days ago",
                    "content": ":-)",
                    "userid": "24",
                    "child": [
                        {
                            "id": "236040",
                            "author_name": "God loves me",
                            "author_url": "https://wx.qlogo.cn/mmopen/vi_32/QTU6iasloiaun5OX6ZcZB964vhHLAc5RuIf8kMR3nwIXvy0HibYOe9RJ9o8escDOIj7MB1vica5ibZ2XSDXIibfQMsJA/132",
                            "date": "1 Days ago",
                            "content": "Why do people choose euthanasia? Can't life be more painful than pain",
                            "userid": "9663",
                            "child": [
                                {
                                    "id": "236042",
                                    "author_name": "Jianbo",
                                    "author_url": "https://wx.qlogo.cn/mmopen/vi_32/Qib5jkFMntPJnT8b2nyzKicoYSuXLeyl07ia1dianxx1fWcic9hJL4UOEuIJvoWWbx7IFia3olUGqiabZvTe0dmeFBicHQ/132",
                                    "date": "1 Days ago",
                                    "content": "If you can't live with dignity, it's hard",
                                    "child": []
                                }
                            ]
                        }
                    ]
                }
            ]
        },
        {
            "id": "236024",
            "author_name": "Advocating adorable",
            "author_url": "../../images/gravatar.png",
            "date": "2019-04-11",
            "content": "Everyone has his unforgettable past. Yesterday, today and tomorrow, try to live every day!",
            "userid": "0",
            "child": [
                {
                    "id": "236041",
                    "author_name": "Jianbo",
                    "author_url": "https://wx.qlogo.cn/mmopen/vi_32/Qib5jkFMntPJnT8b2nyzKicoYSuXLeyl07ia1dianxx1fWcic9hJL4UOEuIJvoWWbx7IFia3olUGqiabZvTe0dmeFBicHQ/132",
                    "date": "1 Days ago",
                    "content": "It's important to have a good day",
                    "userid": "24",
                    "child": []
                }
            ]
        },
        {
            "id": "236018",
            "author_name": "Jielinfan",
            "author_url": "https://wx.qlogo.cn/mmopen/vi_32/Q0j4TwGTfTJBXIvvpMo5nXdlk6Mxwia9chS9E8VHGEQbDmyEAx8opRibztDzmpGHpbC3lR5vh8l4fsScZWoyEWyQ/132",
            "date": "2019-04-08",
            "content": "Best wishes to brother.",
            "userid": "280",
            "child": [
                {
                    "id": "236019",
                    "author_name": "Jianbo",
                    "author_url": "https://wx.qlogo.cn/mmopen/vi_32/Qib5jkFMntPJnT8b2nyzKicoYSuXLeyl07ia1dianxx1fWcic9hJL4UOEuIJvoWWbx7IFia3olUGqiabZvTe0dmeFBicHQ/132",
                    "date": "2019-04-09",
                    "content": ":-)",
                    "userid": "24",
                    "child": []
                }
            ]
        },
        {
            "id": "236017",
            "author_name": "Augmentation net",
            "author_url": "../../images/gravatar.png",
            "date": "2019-04-08",
            "content": "Send you a piece of sea, let you sail smoothly; send you a sun, let you warm and unrestrained; send you a sincere, wish you happy and happy; send you a blessing, let you happy every day!",
            "formId": null,
            "userid": "0",
            "child": []
        },
        {
            "id": "236011",
            "author_name": "Today's news",
            "author_url": "../../images/gravatar.png",
            "date": "2019-04-07",
            "content": "Good article, I like it very much",
            "userid": "0",
            "child": [
                {
                    "id": "236052",
                    "author_name": "Jianbo",
                    "author_url": "https://wx.qlogo.cn/mmopen/vi_32/Qib5jkFMntPJnT8b2nyzKicoYSuXLeyl07ia1dianxx1fWcic9hJL4UOEuIJvoWWbx7IFia3olUGqiabZvTe0dmeFBicHQ/132",
                    "date": "6 Hours ago",
                    "content": "Thank you",
                    "userid": "24",
                    "child": []
                }
            ]
        }
    ]
}

Posted by andco on Mon, 04 May 2020 23:32:08 -0700