You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Socket IO客户端连接后无法推送SQL更新数据问题求助

问题排查与修复方案

核心问题点

  • 代码仅在新客户端触发connection连接事件时才会执行1次数据库查询,没有主动检测数据库变更的逻辑,自然数据库更新后不会主动推送给已在线的客户端
  • 用单个变量connectedSocketID存储连接ID,仅能支持1个客户端同时在线,新客户端连接会覆盖旧ID,多客户端场景无法正常使用
  • JSON.stringify比对对象的实现有隐式缺陷:对象键顺序不同、值为undefined/函数/存在循环引用时都会出现比对错误,可能漏掉真实的数据变更

修复代码

第一步:替换连接存储结构,新增定时轮询检测逻辑

const app = express();
const httpServer = require('http').createServer(app);
const io = require('socket.io')(httpServer);
const path = __dirname + '/views/';
let sqlQuery = require('./controllers/sqlController').queryDatabase;
let currentQueryData = {};
// 替换为Set存储所有在线连接ID,支持多客户端
const connectedSockets = new Set();

app.use(express.static(path))

app.get('/', function (req,res) {
  res.sendFile(path + "index.html");
});

// 函数保留,用于给单个新连接发数据
const sendData = (data, socket) => {
  socket.emit('markerCreation', data); 
}

// 替换为更严谨的深比对逻辑,避免JSON.stringify的坑
const compareObjects = (obj1, obj2) => {
  if (obj1 === obj2) return true;
  if (!obj1 || !obj2 || typeof obj1 !== 'object' || typeof obj2 !== 'object') return false;
  if (Array.isArray(obj1) && Array.isArray(obj2)) {
    if (obj1.length !== obj2.length) return false;
    return obj1.every((item, index) => compareObjects(item, obj2[index]));
  }
  const keys1 = Object.keys(obj1);
  const keys2 = Object.keys(obj2);
  if (keys1.length !== keys2.length) return false;
  return keys1.every(key => keys2.includes(key) && compareObjects(obj1[key], obj2[key]));
}

// 新增定时轮询任务,5秒查询一次数据库,间隔可根据实时性要求调整
setInterval(async () => {
  const newQueryData = await sqlQuery();
  const dataChanged = !compareObjects(currentQueryData, newQueryData);
  if (dataChanged) {
    currentQueryData = newQueryData;
    // 数据变更后广播给所有已连接客户端
    io.emit('markerCreation', currentQueryData);
  }
}, 5000)

httpServer.listen(3001, () => {
  console.log(`Server listening at ${3001}`);
})

io.on('connection', async socket => {
  // 新连接加入在线集合
  connectedSockets.add(socket.id);
  // 新连接直接返回当前最新数据
  const newQueryData = await sqlQuery();
  currentQueryData = newQueryData;
  sendData(currentQueryData, socket);

  // 连接断开时清理资源
  socket.on('disconnect', () => {
    connectedSockets.delete(socket.id);
  });
});

可选优化(更高实时性+更低性能消耗)

如果对数据推送延迟要求很高,不想用轮询产生冗余查询,可以对接SQL Server的变更数据捕获(CDC) 功能,数据库数据有更新时主动触发推送逻辑,无需定时轮询。

内容的提问来源于stack exchange,提问作者jared abbott

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 06:06:04