notification_count字段需手动添加和维护,Laravel不会自动同步;须通过迁移创建、业务逻辑增减、原子操作防并发、精准via配置、合理前端方案及严格测试保障准确性。

notification_count 字段必须手动加,Laravel 不会自动维护
很多人以为 php artisan notifications:table 一跑,未读数就自动同步了——其实完全不是。Laravel 的 notifications 表只存通知记录,notification_count 是纯业务字段,得你亲手加、亲手更新。
-
php artisan make:migration add_notification_count_to_users_table --table=users后,务必在up()里用$table->integer('notification_count')->unsigned()->default(0) - 别漏掉
php artisan migrate,否则字段根本不存在 - 新增通知时不会自动 +1,删除/标记已读时也不会自动 -1——这些逻辑全要你自己写,比如在用户读通知后调用
$user->decrement('notification_count') - 并发场景下(比如多个标签页同时标记已读),直接
decrement()可能出错,更稳妥的是用数据库原子操作:$user->where('id', $user->id)->where('notification_count', '>', 0)->decrement('notification_count')
via() 返回 database 就够了,别盲目加 mail/wechat
红点功能本质是“前端查未读数”,和发不发邮件、推不推微信毫无关系。很多项目硬塞 'mail', 'database' 进 via(),结果配置没配好,Notification::send() 卡住或报错,反而拖慢整个通知写入流程。
- 如果只要红点,
via()只返回['database'],干净又快 - 确保通知类继承
Notification并实现toDatabase(),返回一个轻量数组(别塞模型实例,避免序列化失败) -
toDatabase()里别调用$notifiable->load(...),关联数据应在发送前预加载,否则写库时触发 N+1 - 测试时用
Notification::send($user, new UserRegisteredNotification)看notifications表有没有新记录,别等邮件发出来
前端轮询 or Laravel Echo?选错方案会让红点延迟或压垮服务器
红点要实时,但“实时”不等于每秒请求一次。用错方式,要么用户看到旧数据,要么数据库被轮询打爆。
Laravel Cloud(cloud.laravel.com)。此技能用于处理所有 Laravel Cloud 请求,包括搜索和读取数据。只要任务涉及 Laravel Cloud,即使用此技能。
- 简单后台管理页:用
setInterval(() => axios.get('/api/unread-count'), 30000)(30 秒一次)足够,别设成 1 秒 - 聊天/IM 类场景:必须上
Laravel Echo+redis+private-channel,服务端在写入notifications表后立刻broadcast(new NotificationSent($user)) - 千万别在广播事件里查
count(),而是把notification_count值随事件一起推送,前端直接更新 DOM,避免额外请求 - 如果用 Livewire,注意
$this->user->notification_count在组件内可能缓存,需显式刷新或监听事件更新
notification_count 和实际未读数对不上?大概率是软删除或范围过滤漏了
常见现象:用户明明点了“全部标记为已读”,红点还挂着;或者删了一条通知,数字却没变。问题往往不在计数逻辑本身,而在“未读”的定义没对齐。
-
notifications表默认不带deleted_at,但如果你启用了软删除,whereNull('deleted_at')必须加进所有 count 查询里 - 有些系统按类型过滤红点(比如只算
order_shipped,不算system_alert),那notification_count就不该是总未读,而应是分类型字段,或用缓存键隔离(cache()->get("user_{$id}_order_unread")) - 标记已读接口若用
Notification::markAsRead(),它默认只处理当前用户的通知,但如果通知目标是Notifiable其他模型(如Team),这个方法就不生效,得手写DB::table('notifications')->where(...)->update(['read_at' => now()]) - 上线前务必测「用户 A 发通知 → 用户 B 查红点 → 用户 B 标记已读 → 用户 B 再查红点」全链路,中间任何一步断开,红点就成幽灵数字
红点看着小,但一旦涉及多端同步、软删除、分类统计、高并发标记,很容易在某个边界 case 里悄悄失准。最保险的做法:把 notification_count 当作只读缓存,每次需要精确值时,还是走 DB::table('notifications')->where(...)->count() 拉一次——哪怕慢一点,也比错着强。










