如何在不刷新PHP页面的情况下追踪MySQL数据库的变更?
这需求太典型了——用户提交请求后,管理员操作要实时同步到用户页面,不用刷新。我之前做过类似的工单系统,给你整理几种落地的方案,从易到难,你可以根据项目规模选:
核心实现方案
1. 短轮询(最简单的入门方案)
原理就是前端每隔一段时间主动发请求去MySQL查最新状态,拿到结果后更新页面。优点是零后端额外配置,改改前端加个接口就行,适合小型项目。
前端代码示例(原生JS)
// 定义查询状态的函数 function checkRequestStatus(requestId) { fetch(`/api/get-request-status?requestId=${requestId}`) .then(res => res.json()) .then(data => { const statusElement = document.getElementById(`status-${requestId}`); if (data.status !== statusElement.textContent) { // 更新状态文本,还可以加个样式变化提示用户 statusElement.textContent = data.status; statusElement.style.color = data.status === '已接受' ? 'green' : 'orange'; } }) .catch(err => console.error('查询状态失败:', err)); } // 每隔30秒查一次(时间可以根据需求调) const requestId = '123'; // 这里替换成实际的请求ID setInterval(() => checkRequestStatus(requestId), 30000);
后端接口示例(Node.js + Express + MySQL)
const express = require('express'); const mysql = require('mysql2/promise'); const app = express(); // 创建MySQL连接池 const pool = mysql.createPool({ host: 'localhost', user: 'your_user', password: 'your_password', database: 'your_db' }); // 状态查询接口 app.get('/api/get-request-status', async (req, res) => { const { requestId } = req.query; try { const [rows] = await pool.execute('SELECT status FROM service_requests WHERE id = ?', [requestId]); if (rows.length === 0) { return res.json({ status: '不存在' }); } res.json({ status: rows[0].status }); } catch (err) { res.status(500).json({ error: '查询失败' }); } }); app.listen(3000, () => console.log('服务启动'));
注意:短轮询的缺点是会产生很多无效请求(比如状态没变化的时候),如果用户量大会增加服务器压力,所以时间间隔别设太短。
2. 长轮询(比短轮询更高效)
原理是前端发请求后,后端不会立刻返回结果,而是hold住请求,直到数据库里的状态发生变化,或者超时(比如30秒)才返回。这样能减少请求次数,比短轮询高效很多。
前端代码示例
function longPollRequestStatus(requestId) { fetch(`/api/long-poll-status?requestId=${requestId}`) .then(res => res.json()) .then(data => { // 更新页面状态 const statusElement = document.getElementById(`status-${requestId}`); statusElement.textContent = data.status; statusElement.style.color = data.status === '已接受' ? 'green' : 'orange'; // 请求返回后立刻发起下一次长轮询 longPollRequestStatus(requestId); }) .catch(err => { console.error('长轮询失败:', err); // 失败后延迟几秒再重试,避免频繁请求 setTimeout(() => longPollRequestStatus(requestId), 5000); }); } // 启动长轮询 const requestId = '123'; longPollRequestStatus(requestId);
后端接口示例(Node.js)
app.get('/api/long-poll-status', async (req, res) => { const { requestId } = req.query; let intervalId; // 定时查询数据库,直到状态变化或超时 const checkStatus = async () => { const [rows] = await pool.execute('SELECT status FROM service_requests WHERE id = ?', [requestId]); const currentStatus = rows[0]?.status; // 如果状态不是待处理,就返回结果 if (currentStatus !== '待处理') { clearInterval(intervalId); res.json({ status: currentStatus }); } }; // 每隔2秒查一次数据库 intervalId = setInterval(checkStatus, 2000); // 设置30秒超时,避免请求一直挂着 setTimeout(() => { clearInterval(intervalId); res.json({ status: '待处理' }); // 返回当前状态,前端继续轮询 }, 30000); // 监听客户端断开连接,清理定时器 req.on('close', () => { clearInterval(intervalId); }); });
3. WebSocket(实时性最强,推荐复杂场景)
如果你的项目实时性要求很高(比如管理员操作后用户页面要立刻更新),WebSocket是最佳选择。它是双向通信协议,后端可以主动给前端推送消息,不用前端反复请求。
前端代码示例
// 建立WebSocket连接 const ws = new WebSocket(`ws://localhost:3000/ws?requestId=123`); // 连接成功 ws.onopen = () => { console.log('WebSocket连接成功'); }; // 接收后端推送的消息 ws.onmessage = (event) => { const data = JSON.parse(event.data); const statusElement = document.getElementById(`status-${data.requestId}`); statusElement.textContent = data.status; statusElement.style.color = data.status === '已接受' ? 'green' : 'orange'; }; // 连接关闭时重连 ws.onclose = () => { setTimeout(() => window.location.reload(), 5000); // 或者重新创建连接 };
后端示例(Node.js + ws库 + MySQL)
首先安装ws库:npm install ws
const WebSocket = require('ws'); const wss = new WebSocket.Server({ port: 3000 }); // 存储连接的客户端,key是requestId const clients = new Map(); wss.on('connection', (ws, req) => { const urlParams = new URLSearchParams(req.url.slice(1)); const requestId = urlParams.get('requestId'); // 将客户端连接和requestId关联 if (requestId) { if (!clients.has(requestId)) { clients.set(requestId, []); } clients.get(requestId).push(ws); } // 客户端断开连接时移除 ws.on('close', () => { if (requestId && clients.has(requestId)) { clients.set(requestId, clients.get(requestId).filter(client => client !== ws)); if (clients.get(requestId).length === 0) { clients.delete(requestId); } } }); }); // 当管理员更新状态时,推送消息给对应客户端 app.post('/api/update-request-status', async (req, res) => { const { requestId, status } = req.body; try { await pool.execute('UPDATE service_requests SET status = ? WHERE id = ?', [status, requestId]); // 推送给所有关注这个requestId的客户端 if (clients.has(requestId)) { clients.get(requestId).forEach(client => { if (client.readyState === WebSocket.OPEN) { client.send(JSON.stringify({ requestId, status })); } }); } res.json({ success: true }); } catch (err) { res.status(500).json({ error: '更新失败' }); } });
方案选择建议
- 小型项目/需求简单:用短轮询,开发快,成本低。
- 中型项目/想减少请求:用长轮询,比短轮询高效,又不用改太多架构。
- 大型项目/高实时性要求:用WebSocket,体验最好,适合频繁更新的场景。
内容的提问来源于stack exchange,提问作者Pavan Kumar Lekkala
相关产品推荐
相关产品推荐

