hl-api-changelog/changelogs/2026-05/09_fix_mp_message_read_status_bugs.md
API Changelog Bot f8d53fb3b5 fix: mp 消息已读/未读 4 项 bug 修复 (PR #1912 / Issue #1911)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 12:25:15 +08:00

4.1 KiB

mp 消息已读/未读 4 项 bug 修复(性能 + 正确性)

服务: hl-user-service(8081) PR: #1912 Issue: #1911 日期: 2026-05-09 影响范围: 小程序消息中心 / badge 未读数 / 消息列表


⚠️ 关键变化(无新增字段,纯修复 + 性能优化)

  1. B1 单条标已读接口真正生效(原是空实现)
  2. B2 标已读后 badge 红点秒级刷新(原 30s 缓存不刷)
  3. B3 消息列表接口零阻塞(原同步 UPDATE 主线程,慢)
  4. B4 加联合索引加速 UPDATE/SELECT(原全表扫)

前端无需改造


一、变更接口行为

接口 路径 行为变更
单条标已读 PUT /mp/message/{id}/read 真正更新 DB(原空实现);标已读后 badge 立即刷新
全部标已读 PUT /mp/message/read-all UPDATE 后立即失效缓存(原 30s 后才刷)
分类标已读 PUT /mp/message/read-all?category=xxx 同上
消息列表 GET /mp/message/list 响应不再阻塞 UPDATE:主线程返回时内存里已 isRead=true,DB 异步落
消息摘要 GET /mp/message/summary 缓存失效更准(deps table:user_message 联动)

二、Bug 详情

B1 单条标已读真实现

修前:InternalMpMessageController.markRead(messageId) 是空方法,只返 success,DB 不更新。 修后:调 UserMessageService.markRead(messageId, userId)UPDATE user_message SET is_read=1 WHERE id=? AND user_id=? AND is_read=0

  • WHERE 限定 user_id 防越权(原本相信前端传入)
  • 已读消息再标 → rows=0(幂等)

B2 缓存失效

修前:markAllRead/markCategoryRead UPDATE 后没通知 /mp/message/summary 缓存(@MpCache(ttl=30, deps={"table:user_message"})),badge 红点 30 秒内显示旧数。 修后:三处方法都加 afterCommitdepsManager.invalidateSource("table:user_message"),事务提交后立即失效缓存。

B3 listMessages 异步标已读

修前:UserMessageService.listMessages 内部同步 UPDATE 当前分类为已读,主线程阻塞修后:

  • 引入独立 bean UserMessageReadAsyncTask(绕 @Async self-invocation)
  • @Async("messageReadExecutor") 独立线程池(core=3, max=8, queue=100)
  • 主线程内存里 setIsRead(1) 立即返 RespVO,DB 异步落

前端体验:消息列表打开毫秒级返回(原阻塞数百毫秒),已读状态展示无滞后。

B4 联合索引

修前:user_message 表只有 idx_user_category(user_id, category_code) + idx_create_time(create_time),WHERE user_id=? AND is_read=0 走全表扫(尤其在用户消息多时)。 修后:Flyway V20260509_001 加 idx_user_read(user_id, is_read) 联合索引,加速:

  • 标已读 UPDATE
  • 未读数 SELECT(/mp/message/summary)
  • 全分类标已读 UPDATE

三、向后兼容

  • API 字段无变化
  • 前端不需要任何改造
  • 单条 markRead 接口路径不变,只是真生效了
  • 老消息(is_read=NULL)由 VO 转换层 isRead != null && isRead == 1 防护(已存在)

四、测试覆盖

  • UserMessageServiceTest +13(markRead valid/wrong-user/already-read,markAllRead/markCategoryRead 缓存失效,listMessages async + 内存 isRead)
  • InternalMpMessageControllerTest +1(markRead 调 service)
  • UserMessageReadAsyncTaskTest 3(异步执行 + 异常 swallow)
  • 共 28 全绿

测试服已部署回归:

  • user-service 双实例(8081+8181)新进程启动
  • Flyway V20260509_001 落库,idx_user_read 联合索引就位

五、部署注意(运维)

测试服首次部署 V20260509_001 时遇到 Duplicate key name 'idx_user_read'(疑似历史手动加过同名索引未记录),Flyway 标 success=0,服务启动失败。已通过 SQL UPDATE flyway_schema_history SET success=1 WHERE version='20260509.001' 修复

正式部署前:运维确认 prod user_message 表是否已存在 idx_user_read 索引,如有需提前 SQL 设 history success=1 或 DROP 旧索引。

六、@mmg 关注点

无前端改造。本期纯后端修复,前端体验改善:

  1. badge 红点秒级刷新(原延迟 30s)
  2. 消息列表打开零阻塞
  3. 单条标已读真生效(原前端可能调了无效)