如何高效实现多用户通知系统而不重复存储消息

星涛吖_8427

星涛吖_8427

2026-03-29

662人浏览

原创

如何高效实现多用户通知系统而不重复存储消息

本文介绍一种基于关系型数据库的轻量级通知系统设计,通过分离“通知模板”与“用户状态”两张表,避免消息冗余存储,同时支持全员广播、已读标记和高并发写入。

本文介绍一种基于关系型数据库的轻量级通知系统设计,通过分离“通知模板”与“用户状态”两张表,避免消息冗余存储,同时支持全员广播、已读标记和高并发写入。

在构建面向多用户的 Web 通知系统(如后台管理员向全体用户发送公告)时,一个常见误区是为每位用户单独插入一条完整通知记录——这不仅浪费存储空间,还会显著增加写入压力、降低查询效率,并给后续统计(如“未读数”)带来复杂性。正确的做法是采用模板化+状态映射的设计范式:将通知内容本身抽象为不可变的“模板”,而将用户个体行为(是否已读、何时阅读)作为独立的状态记录。

✅ 推荐数据库结构设计

建议创建两张表,职责清晰、无冗余:

-- 表1:notifications —— 存储通知元数据(一次写入,永久复用)
CREATE TABLE notifications (
  id INT PRIMARY KEY AUTO_INCREMENT,
  title VARCHAR(255) NOT NULL,
  content TEXT NOT NULL,
  created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
  is_active TINYINT(1) DEFAULT 1  -- 支持软删除或停用历史通知
);

-- 表2:user_notifications —— 记录每个用户对该通知的状态(按需生成)
CREATE TABLE user_notifications (
  id BIGINT PRIMARY KEY AUTO_INCREMENT,
  notification_id INT NOT NULL,
  user_id INT NOT NULL,
  is_read TINYINT(1) DEFAULT 0,
  read_at DATETIME NULL,
  created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
  UNIQUE KEY uk_user_notif (user_id, notification_id), -- 防止重复关联
  FOREIGN KEY (notification_id) REFERENCES notifications(id) ON DELETE CASCADE,
  FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
);

? 关键设计说明:

  • notifications 表仅存一份原始消息,无论有多少用户,新增通知只需 1 次 INSERT;
  • user_notifications 表在发送通知时批量插入(非实时逐条),例如使用 INSERT ... SELECT 将所有活跃用户 ID 与新通知 ID 关联;
  • UNIQUE KEY uk_user_notif 确保同一用户对同一通知不会重复记录,规避逻辑错误。

? 发送全员通知的正确 SQL 实现(关键步骤)

当管理员发布一条新通知后,需将其“分发”给目标用户群体(如所有启用账户)。此时应执行原子性批量插入,而非循环 PHP 插入:

-- 步骤1:插入通知模板
INSERT INTO notifications (title, content) 
VALUES ('系统维护提醒', '平台将于今晚23:00-24:00进行例行维护,请提前保存工作。');

-- 步骤2:获取刚插入的通知ID(假设为 LAST_INSERT_ID() = 123)
-- 步骤3:批量关联所有符合条件的用户(推荐使用事务保障一致性)
START TRANSACTION;

INSERT INTO user_notifications (notification_id, user_id)
SELECT 123, id 
FROM users 
WHERE status = 'active' AND deleted_at IS NULL;

COMMIT;

✅ 该方式仅需 2 条 SQL 语句 + 1 次事务,即可完成“1 条消息 → N 个用户”的状态初始化,性能远超 N 次单条插入,且天然避免竞态与重复。

⚠️ 注意事项与最佳实践

  • 不要在应用层循环插入:PHP 中 foreach ($users as $u) { INSERT ... } 是性能杀手,尤其在用户量达万级时极易触发连接超时或锁表;
  • 合理使用索引:在 user_notifications(notification_id, is_read) 和 (user_id, is_read) 上建立复合索引,加速「某用户未读列表」和「某通知已读人数」两类高频查询;
  • 延迟加载状态:首次访问通知中心时再生成 user_notifications 记录(即“懒分发”),适用于低频通知场景;但对强时效性通知(如紧急告警),建议同步批量写入;
  • 清理策略:可定期归档或删除 is_read = 1 AND read_at
  • 事务不是万能的:虽然 INSERT ... SELECT 本身具备原子性,但若业务含更复杂逻辑(如积分变动、日志记录),务必包裹 START TRANSACTION ... COMMIT/ROLLBACK。

✅ 总结

真正的可扩展通知系统不靠“复制消息”,而靠“解耦内容与状态”。通过 notifications + user_notifications 的二表结构,你既能保证消息源头唯一、存储零冗余,又能灵活支持已读/未读、批量标记、统计分析等全部功能。配合批量 SQL 与事务控制,即便面对数十万用户,也能在毫秒级完成全员触达——这才是现代 Web 应用应有的数据设计思维。

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
php文件怎么打开
php文件怎么打开

打开php文件步骤:1、选择文本编辑器;2、在选择的文本编辑器中,创建一个新的文件,并将其保存为.php文件;3、在创建的PHP文件中,编写PHP代码;4、要在本地计算机上运行PHP文件,需要设置一个服务器环境;5、安装服务器环境后,需要将PHP文件放入服务器目录中;6、一旦将PHP文件放入服务器目录中,就可以通过浏览器来运行它。

2023.09.01

11944

6

php怎么取出数组的前几个元素
php怎么取出数组的前几个元素

取出php数组的前几个元素的方法有使用array_slice()函数、使用array_splice()函数、使用循环遍历、使用array_slice()函数和array_values()函数等。本专题为大家提供php数组相关的文章、下载、课程内容,供大家免费下载体验。

2023.10.11

6841

5

php反序列化失败怎么办
php反序列化失败怎么办

php反序列化失败的解决办法检查序列化数据。检查类定义、检查错误日志、更新PHP版本和应用安全措施等。本专题为大家提供php反序列化相关的文章、下载、课程内容,供大家免费下载体验。

2023.10.11

2195

5

php怎么连接mssql数据库
php怎么连接mssql数据库

连接方法:1、通过mssql_系列函数;2、通过sqlsrv_系列函数;3、通过odbc方式连接;4、通过PDO方式;5、通过COM方式连接。想了解php怎么连接mssql数据库的详细内容,可以访问下面的文章。

2023.10.23

4348

4

php连接mssql数据库的方法
php连接mssql数据库的方法

php连接mssql数据库的方法有使用PHP的MSSQL扩展、使用PDO等。想了解更多php连接mssql数据库相关内容,可以阅读本专题下面的文章。

2023.10.23

5074

6

html怎么上传
html怎么上传

html通过使用HTML表单、JavaScript和PHP上传。更多关于html的问题详细请看本专题下面的文章。php中文网欢迎大家前来学习。

2023.11.03

3991

9

PHP出现乱码怎么解决
PHP出现乱码怎么解决

PHP出现乱码可以通过修改PHP文件头部的字符编码设置、检查PHP文件的编码格式、检查数据库连接设置和检查HTML页面的字符编码设置来解决。更多关于php乱码的问题详情请看本专题下面的文章。php中文网欢迎大家前来学习。

2023.11.09

5757

8

php文件怎么在手机上打开
php文件怎么在手机上打开

php文件在手机上打开需要在手机上搭建一个能够运行php的服务器环境,并将php文件上传到服务器上。再在手机上的浏览器中输入服务器的IP地址或域名,加上php文件的路径,即可打开php文件并查看其内容。更多关于php相关问题,详情请看本专题下面的文章。php中文网欢迎大家前来学习。

2023.11.13

4502

8

sprintf函数用法详解
sprintf函数用法详解

sprintf函数的用法:1、格式化字符串;2、指定输出宽度和精度;3、返回值。更多关于sprintf函数用法详解的内容,大家可以阅读下面的文章。

2023.11.27

12382

4

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
热门推荐
/
最新课程
phpStudy极速入门视频教程
phpStudy极速入门视频教程

共6课时 | 54.7万人学习

独孤九贱(4)_PHP视频教程
独孤九贱(4)_PHP视频教程

共89课时 | 134.1万人学习