前段时间设计了系统的评论模块,并写了篇文章 评论模块 - 后端数据库设计及功能实现 讲解。
大佬们在评论区提出了些优化建议,总结一下:
- 之前评论一共分了两张表,一个评论主表,一个回复表。这两张表的字段区别不大,在主表上加个 pid 字段就可以不用回复表合成一张表了。
- 评论表中存了用户头像,会引发一些问题。比如用户换头像时要把评论也一起更新不太合适,还可能出现两条评论头像不一致的情况。
的确数据库设计的有问题,感谢 wangbjun 和 JWang。
下面就对评论模块进行优化改造,首先更改表结构,合成一张表。评论表不存用户头像的话,需要从用户服务获取。用户服务提供获取头像的接口,两个服务间通过 Feign 通信。
这样有个问题,如果一个资源的评论比较多,每个评论都调用用户服务查询头像还是有点慢,所以对评论查询加个 Redis 缓存。要是有新的评论,就把这个资源缓存的评论删除,下次请求时重新读数据库并将最新的数据缓存到 Redis 中。
代码出自开源项目
coderiver
,致力于打造全平台型全栈精品开源项目。
项目地址:https://github.com/cachecats/coderiver
本文将分四部分介绍
- 数据库改造
- 用户服务提供获取头像接口
- 评论服务用 Feign 访问用户服务取头像
- 使用 Redis 缓存数据
一、数据库改造
数据库表重新设计如下
CREATE TABLE `comments_info` (
`id` varchar(32) NOT NULL COMMENT '评论主键id',
`pid` varchar(32) DEFAULT '' COMMENT '父评论id',
`owner_id` varchar(32) NOT NULL COMMENT '被评论的资源id,可以是人、项目、资源',
`type` tinyint(1) NOT NULL COMMENT '评论类型:对人评论,对项目评论,对资源评论',
`from_id` varchar(32) NOT NULL COMMENT '评论者id',
`from_name` varchar(32) NOT NULL COMMENT '评论者名字',
`to_id` varchar(32) DEFAULT '' COMMENT '被评论者id',
`to_name` varchar(32) DEFAULT '' COMMENT '被评论者名字',
`like_num` int(11) DEFAULT '0' COMMENT '点赞的数量',
`content` varchar(512) DEFAULT NULL COMMENT '评论内容',
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
PRIMARY KEY (`id`),
KEY `owner_id` (`owner_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='评论表';
相比之前添加了父评论id pid
,去掉了用户头像。owner_id
是被评论的资源id,比如一个项目下的所有评论的 owner_id
都是一样的,便于根据资源 id 查找该资源下的所有评论。
与数据表对应的实体类 CommentsInfo
package com.solo.coderiver.comments.dataobject;
import lombok.Data;
import org.hibernate.annotations.DynamicUpdate;
import javax.persistence.Entity;
import javax.persistence.Id;
import java.io.Serializable;
import java.util.Date;
/**
* 评论表主表
*/
@Entity
@Data
@DynamicUpdate
public class CommentsInfo implements Serializable{
private static final long serialVersionUID = -4568928073579442976L;
//评论主键id
@Id
private String id;
//该条评论的父评论id
private String pid;
//评论的资源id。标记这条评论是属于哪个资源的。资源可以是人、项目、设计资源
private String ownerId;
//评论类型。1用户评论,2项目评论,3资源评论
private Integer type;
//评论者id
private String fromId;
//评论者名字
private String fromName;
//被评论者id
private String toId;
//被评论者名字
private String toName;
//获得点赞的数量
private Integer likeNum;
//评论内容
private String content;
//创建时间
private Date createTime;
//更新时间
private Date updateTime;
}
数据传输对象 CommentsInfoDTO
在 DTO 对象中添加了用户头像,和子评论列表 children
,因为返给前端要有层级嵌套。
package com.solo.coderiver.comments.dto;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;