tp6聊天记录存储采用mysql主存+redis缓存组合方案,精简表结构、合理建索引、分层加载查询,并通过敏感词过滤、状态标记、软删除及合规导出保障安全与合规。

TP6 接口实现聊天记录存储,核心在于结构设计、写入效率与查询便利性的平衡。不推荐全量存进 Redis 或仅用文件缓存,应以 MySQL 为主存 + Redis 辅助加速的组合方式落地。
消息表结构要精简且带索引
每条消息必须有明确归属(单聊 or 群聊),状态字段要预留扩展空间:
- 单聊场景:用 sender_id 和 receiver_id 双向标识,查询时按“我发给谁”或“谁发给我”走不同索引
- 群聊场景:用 group_id 替代 receiver_id,并加 is_at 字段标记是否被@
- 关键索引至少建三个:(sender_id, create_time)、(receiver_id, create_time)、(group_id, create_time),避免深分页慢查
- content 字段建议用 TEXT 类型,但图片/语音等大内容只存 URL,原始文件走对象存储
TP6 中封装可复用的消息写入逻辑
不要在控制器里直接 new Model()->save(),应在 service 层统一处理:
ThinkPHP 6.0.0 是国产轻量级 PHP 框架的里程碑式版本,于 2019 年正式发布。该版本基于“精简核心”与“统一用法”原则,对底层架构进行了彻底重构。它强制要求 PHP 7.1+ 环境,全面启用强类型声明,深度支持 PSR 规范,并引入了独立的多应用模式、改进的中间件机制及全新的事件系统,标志着 ThinkPHP 正式迈入现代化、标准化与企业级开发的新阶段。
- 接收参数后先校验 sender_id 与当前登录用户一致,防止伪造发信人
- 自动补全 status = 'sent'、timestamp = time(),避免前端传时间导致偏差
- 插入成功后,用 Redis 的 LPUSH msg:list:{user_id} 缓存最近 100 条 ID,用于快速拉取会话列表
- 异步触发消息队列(如 think-queue)做后续动作:未读计数更新、消息搜索入库、敏感词扫描
读取时兼顾性能与一致性
用户打开聊天窗口时,不是查全表,而是分层加载:
- 首次加载:查 msg:list:{user_id} 拿到最新 20 条 ID,再 IN 查询主表 拼完整消息
- 上拉翻页:用 last_msg_id 做条件查询,例如
WHERE id ,避免 OFFSET 性能衰减 - 已读状态不依赖实时 SELECT,而用 Redis Bitmap 单独维护(key 为 msg:read:{msg_seq},bit 位对应 user_offset),查读态只需 getBit 一次调用
- 未读总数用 Redis 的 INCR msg:unread:{user_id} 维护,发消息时 +1,标已读时 -1,比每次 COUNT(*) 快得多
注意数据安全与合规底线
婚恋社交类系统对聊天内容监管更严,不能只存不管:
- 所有消息入库前过一遍敏感词库(可用 Redis Set 存热词,O(1) 判断)
- 实名认证未通过的用户,消息 status 标记为 'pending_review',后台审核通过才改为 'sent'
- 用户注销账号时,不是 DELETE,而是 UPDATE SET status = 'deleted_by_user',保留审计依据
- 按《个人信息保护法》要求,支持导出本人全部聊天记录(含时间、对方昵称脱敏、内容原文),接口需加二次密码验证










