WebSocket本身不提供定时能力,真正控制推送频率的是后端定时任务;它仅作为通信通道负责消息传输,定时逻辑需由@Scheduled等机制实现。

WebSocket 推送靠定时任务触发,不是协议自带的“定时”能力
很多人一看到“WebSocket 定时推送”,就以为 WebSocket 协议本身支持设置 5 秒发一次、10 秒发一次。其实不是。WebSocket 只是一条双向通道,它不决定“什么时候发”,只负责“怎么发”。真正控制频率的,是后端的定时调度逻辑。
常见错误现象:前端连上了,但一直没收到消息;或者消息忽多忽少、时间间隔不稳定。
- 根本原因往往是定时任务没配对——比如用了
@Scheduled(fixedDelay = 10000),但没加@EnableScheduling,导致方法压根没执行 - Spring Boot 中,
@Scheduled默认只在单机生效;集群部署时,多个节点会同时推送,造成重复发送 - 如果定时任务里查 DB 或调外部接口耗时过长(比如 >5s),而
fixedDelay设的是 10s,就可能堆积任务,甚至线程阻塞
数据库变更监听推送(Oracle CDC 类方案)需注意连接生命周期和字段粒度
这是目前最接近“真实时”的方式:数据库一改,立刻通知服务端,再推给前端。但它依赖 Oracle 的 DBMS_ALERT 或 UTL_HTTP 回调,或更现代的 LogMiner / GoldenGate 集成。
容易踩的坑集中在两个地方:
立即学习“前端免费学习笔记(深入)”;
将一个或多个 UI 原型图、线框图、产品截图或设计稿转换为标准化、可直接交付的 PRD 风格文档,供产品、设计、前端和测试共同使用。适用于 Codex 需要分析 PC 网页、桌面端、移动端、响应式页面、独立弹窗、表单、表格、看板、数据大屏或多页面流程截图,还原页面结构与交互,强制套用固定文档模板,抽取跨页面共享规则,或把一组原型沉淀为单页规范文档加整体业务流程文档的场景。不适用于纯视觉审美点评、代码实现、接口设计、埋点方案、竞品分析或无 UI 输入的业务需求创作。
- 监听器注册后,如果应用重启或 WebSocket 连接断开,Oracle 端的回调可能仍在发,但服务端已无处接收,导致消息丢失或报错
Connection refused - Oracle 触发器 + HTTP 回调的方式,无法区分“哪一行、哪个字段变了”,容易误推整张表;若想只推
status字段变更,必须在触发器里显式比对:OLD.status != :NEW.status - 该方案对 Oracle 权限要求高(如需要
EXECUTE ON UTL_HTTP),测试环境常因权限不足直接失败
增删改操作后同步推送,要注意事务边界和连接可用性
这是开发中最常用、也最容易出问题的方式:用户保存订单 → 后端写 DB → 成功后立即调用 websocketSendUtil.sendToAll()。
关键点不在“怎么发”,而在“什么时候能安全发”:
- 如果推送逻辑写在 service 层,但事务还没提交(比如用了
@Transactional且传播行为是REQUIRED),DB 写入可能被回滚,而消息已经发出去了,造成前后端状态不一致 - 必须确保推送前,目标 WebSocket 连接还活着:
session.isOpen()要判断,否则调session.getBasicRemote().sendText()会抛IllegalStateException: The session is invalid - 不要在 Controller 层直接调推送工具类——Controller 返回响应后连接可能已关闭;应放在事务提交后的回调中,例如用
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
前端连接管理不当,会让所有推送都变成“发给了空气”
后端代码再正确,只要没把消息送到正确的 Session,就等于没推。而 Session 的生命周期极短且易失。
典型问题包括:
- 用
ConcurrentHashMap<string session></string>存连接,但 key 是用户 ID,却没处理用户登出或 Token 过期后的清理,导致向已失效的 Session 发送数据,抛IOException: Broken pipe - 前端页面刷新或关闭标签页时,
onclose事件未必触发(比如网络突然中断),服务端无法感知,连接对象滞留内存,越积越多 - 没做心跳保活,Nginx/Tomcat 默认 60 秒超时断连,但后端仍以为连接有效,继续往里塞消息
最常被忽略的一点:WebSocket 连接是绑定到具体 Tomcat 实例的。如果你用 Nginx 做负载均衡又没配 sticky session,用户第一次连 A 节点,第二次请求落到 B 节点,B 节点根本不知道这个用户连在哪,自然无法精准推送。

















