当前位置:首页 > 数据库 > 正文

仿qq留言板数据库怎么设计

建三张表:用户表(uid,昵称)、留言表(mid,uid,内容,时间)、回复表(rid,mid,uid,内容),通过外键关联实现层级化

在设计一个仿QQ留言板功能的数据库时,需围绕核心业务场景(用户发表留言、回复留言、点赞互动、通知提醒)展开,兼顾数据完整性、查询效率与扩展性,以下从需求分析→表结构设计→字段说明→索引优化→关联关系→关键业务逻辑实现→安全与维护七个维度详细说明,并附完整表结构示例及FAQ。


需求拆解与核心实体识别

仿QQ留言板的典型功能包括:
用户可向他人/自己的主页发送文字+表情的留言;
接收方可对留言进行回复(一级/多级嵌套);
其他用户能对留言或回复点赞;
系统需推送新留言/回复的通知给用户;
支持按时间、热度排序查看历史记录;
涉及敏感词过滤、防刷赞等基础风控。

由此提取核心实体:用户(User)、留言(Message)、回复(Reply)、点赞(Like)、通知(Notification)


详细表结构设计(含字段注释)

用户表 user(存储用户基本信息)

字段名 类型 约束 说明
user_id BIGINT(20) PRIMARY KEY AUTO_INCREMENT 用户唯一标识(建议用UUIDv4替代自增ID防暴露注册量)
username VARCHAR(50) NOT NULL UNIQUE 登录名(需全局唯一)
password_hash VARCHAR(255) NOT NULL BCrypt加密后的密码(禁止明文存储)
avatar_url VARCHAR(512) 头像OSS地址(如https://xxx.com/avatar/xxx.jpg)
nickname VARCHAR(30) NOT NULL 昵称(前端展示用)
create_time DATETIME DEFAULT CURRENT_TIMESTAMP 账号创建时间
update_time TIMESTAMP ON UPDATE CURRENT_TIMESTAMP 最后修改时间(用于排序)
status TINYINT(1) DEFAULT 1 账号状态(1=正常,0=封禁,-1=注销)

注意:若需区分“好友”“陌生人”等关系,可额外建friend_ship表存储双向关注关系。

留言表 message(核心业务表)

字段名 类型 约束 说明
msg_id BIGINT(20) PRIMARY KEY AUTO_INCREMENT 留言唯一ID
from_user_id BIGINT(20) NOT NULL 留言发送者ID(关联user.user_id
to_user_id BIGINT(20) NOT NULL 留言接收者ID(关联user.user_id
content LONGTEXT NOT NULL (支持富文本,需转义特殊字符防XSS攻击)
emoji_list JSON 表情列表(如[{“type”:”heart”,”count”:3}],便于前端渲染)
create_time DATETIME DEFAULT CURRENT_TIMESTAMP 留言创建时间(用于排序)
update_time TIMESTAMP ON UPDATE CURRENT_TIMESTAMP 最后修改时间
is_public TINYINT(1) DEFAULT 1 可见性(1=公开,0=仅双方可见,适用于私密对话场景)
parent_msg_id BIGINT(20) NULL 父留言ID(若为空则是顶级留言,非空则为回复某条留言)
reply_count INT DEFAULT 0 该留言下的回复总数(冗余字段,避免每次统计)
like_count INT DEFAULT 0 获赞总数(冗余字段,提升读取效率)

关键设计点

  • parent_msg_id实现留言树形结构(顶级留言无父ID,回复指向父留言ID);
  • reply_countlike_count采用“计数器”模式,当新增回复/点赞时直接+1,避免实时统计带来的性能损耗;
  • is_public控制权限,例如A给B发的私密留言,C无法查看。

回复表 reply(存储对留言的具体回复)

字段名 类型 约束 说明
reply_id BIGINT(20) PRIMARY KEY AUTO_INCREMENT 回复唯一ID
msg_id BIGINT(20) NOT NULL 所属留言ID(关联message.msg_id
from_user_id BIGINT(20) NOT NULL 回复者ID(关联user.user_id
content LONGTEXT NOT NULL
create_time DATETIME DEFAULT CURRENT_TIMESTAMP 回复创建时间
quote_text VARCHAR(255) 引用的原留言片段(可选,提升交互体验)

说明:一条留言可对应多条回复(1:N关系),通过msg_id建立关联。

点赞表 like_record(记录用户对留言/回复的点赞行为)

字段名 类型 约束 说明
like_id BIGINT(20) PRIMARY KEY AUTO_INCREMENT 点赞记录唯一ID
target_type TINYINT(1) NOT NULL 点赞目标类型(1=留言,2=回复)
target_id BIGINT(20) NOT NULL 目标ID(若target_type=1则为message.msg_id;若=2则为reply.reply_id
user_id BIGINT(20) NOT NULL 点赞用户ID(关联user.user_id
create_time DATETIME DEFAULT CURRENT_TIMESTAMP 点赞时间

关键设计点

  • target_type区分点赞对象是留言还是回复,避免混淆;
  • 同一用户对同一目标仅能点赞一次(需通过唯一索引约束:UNIQUE(target_type, target_id, user_id))。

通知表 notification(系统消息队列)

字段名 类型 约束 说明
notif_id BIGINT(20) PRIMARY KEY AUTO_INCREMENT 通知唯一ID
user_id BIGINT(20) NOT NULL 接收通知的用户ID(关联user.user_id
action_type TINYINT(1) NOT NULL 通知类型(1=新留言,2=新回复,3=被点赞)
source_id BIGINT(20) NOT NULL 触发通知的来源ID(如留言ID、回复ID)
content VARCHAR(255) NOT NULL 通知简要内容(如“用户张三给你留了言”)
is_read TINYINT(1) DEFAULT 0 是否已读(0=未读,1=已读)
create_time DATETIME DEFAULT CURRENT_TIMESTAMP 通知生成时间

作用:通过轮询或WebSocket推送未读通知给用户,提升实时性。


表间关联关系(ER图逻辑)

  • 用户↔留言:一个用户可以发送多条留言(1:N),也可以接收多条留言(1:N);
  • 留言↔回复:一条留言可被多次回复(1:N),回复必须归属某条留言;
  • 用户↔点赞:一个用户可以给多个留言/回复点赞(1:N),但同一目标仅能点赞一次;
  • 用户↔通知:一个用户可以收到多条通知(1:N),通知指向具体的业务事件。

索引优化策略(提升查询性能)

表名 推荐索引 适用场景
user idx_username (username), idx_status (status) 快速查找用户/筛选活跃用户
message idx_from_user_id (from_user_id), idx_to_user_id (to_user_id), idx_create_time (create_time DESC) 查询某人发送的留言/接收的留言/最新留言
reply idx_msg_id (msg_id), idx_create_time (create_time DESC) 查询某条留言的所有回复/最新回复
like_record idx_target_type_target_id (target_type, target_id), idx_user_id (user_id) 统计某条留言的点赞数/查询用户的点赞记录
notification idx_user_id_is_read (user_id, is_read), idx_action_type (action_type) 查询用户的未读通知/分类通知

注意:复合索引顺序遵循“左前缀原则”,例如idx_target_type_target_id应先按target_type排序,再按target_id排序,以匹配查询条件WHERE target_type=1 AND target_id=XXX


关键业务逻辑实现示例

发表留言流程

-步骤1:插入留言记录
INSERT INTO `message` (from_user_id, to_user_id, content, is_public, parent_msg_id)
VALUES (#{fromUserId}, #{toUserId}, #{content}, #{isPublic}, #{parentMsgId}); -parentMsgId为空则是顶级留言
-步骤2:更新接收者的未读通知计数(可选,若需显示“你有X条未读留言”)
UPDATE `user` SET unread_count = unread_count + 1 WHERE user_id = #{toUserId};
-步骤3:生成通知(若接收者在线则推送WebSocket)
INSERT INTO `notification` (user_id, action_type, source_id, content)
VALUES (#{toUserId}, 1, LAST_INSERT_ID(), '用户#{fromUsername}给你留了言');

点赞留言流程(含幂等性校验)

-检查是否已点赞过(防止重复点赞)
SELECT  FROM `like_record` 
WHERE target_type = 1 AND target_id = #{msgId} AND user_id = #{userId};
-如果未点赞,则插入记录并更新留言的like_count
IF NOT EXISTS (上述结果) THEN
    INSERT INTO `like_record` (target_type, target_id, user_id)
    VALUES (1, #{msgId}, #{userId});
    UPDATE `message` SET like_count = like_count + 1 WHERE msg_id = #{msgId};
END IF;

查询某用户接收的所有留言(含回复和点赞数)

SELECT 
    m.msg_id, m.from_user_id, u.nickname AS from_nickname, u.avatar_url,
    m.content, m.create_time, m.like_count, m.reply_count,
    (SELECT COUNT() FROM `reply` r WHERE r.msg_id = m.msg_id) AS actual_reply_count -双重校验冗余字段准确性
FROM `message` m
JOIN `user` u ON m.from_user_id = u.user_id
WHERE m.to_user_id = #{currentUserId} AND m.is_public = 1 -只查公开留言
ORDER BY m.create_time DESC
LIMIT #{pageSize} OFFSET #{offset};

安全与维护注意事项

  1. 数据安全

    • 密码必须使用BCrypt等不可逆算法加密;
    • 接口需做身份鉴权(如JWT令牌),防止越权访问他人留言;
    • 需过滤HTML标签(如
0