当前位置: 首页 > article >正文

Web 实时通信技术:WebSocket 与 Server-Sent Events (SSE) 深入解析

一、WebSocket:

(一)WebSocket 是什么?

WebSocket 是一种网络通信协议,它提供了一种在单个 TCP 连接上进行全双工通信的方式。与传统的 HTTP 请求 - 响应模型不同,WebSocket 允许服务器和客户端在连接建立后随时互相发送数据,而无需重新建立连接。这种特性使得它在实时交互场景中具有得天独厚的优势。

(二)WebSocket 的工作原理

  1. 连接建立:WebSocket 的连接过程始于一个 HTTP 请求。客户端通过在 HTTP 请求中添加特定的 Upgrade 和 Connection 头,向服务器发起 WebSocket 升级请求。服务器如果支持 WebSocket,会返回一个 101 Switching Protocols 响应,表示连接已升级为 WebSocket。值得注意的是,在实际应用中,一些代理服务器或防火墙可能会对 WebSocket 的连接请求进行拦截,开发者需要进行相应的配置以确保连接顺利建立。
  1. 数据传输:一旦连接建立,客户端和服务器就可以通过帧的形式互相发送数据。WebSocket 支持多种数据类型,包括文本、二进制数据等。为了提高数据传输效率,在传输大量数据时,可以对数据进行压缩处理,例如使用 Gzip 压缩算法,减少网络传输的数据量。
  1. 连接关闭:WebSocket 连接可以通过发送关闭帧来终止。关闭帧中可以包含关闭原因和状态码,便于调试和错误处理。在实际开发中,还需要考虑异常情况下的连接关闭处理,比如网络中断导致的连接意外关闭,此时需要及时进行重连操作以保证通信的连续性。

(三)WebSocket 的应用场景

  • 实时聊天应用:WebSocket 是聊天应用的理想选择。它允许服务器在收到消息后立即推送给其他用户,无需客户端轮询服务器。以 Slack 为例,它基于 WebSocket 实现了高效的实时聊天功能,用户在发送消息后几乎能瞬间看到对方的回复,极大地提升了沟通效率。
  • 在线游戏:游戏需要低延迟的通信来实时更新游戏状态。WebSocket 的全双工特性能够满足这一需求。像《Among Us》这样的在线游戏,通过 WebSocket 实现了玩家之间实时的信息交互,包括角色位置、动作、对话等,保证了游戏的流畅性和趣味性。
  • 实时数据可视化:例如股票行情、体育赛事比分等,WebSocket 可以实时推送数据到客户端进行展示。在金融领域,许多在线交易平台利用 WebSocket 实时更新股票价格、交易数据等信息,帮助投资者及时做出决策。

(四)WebSocket 的优缺点

优点

  • 低延迟:一旦连接建立,数据传输无需重新建立连接,大大减少了通信延迟。在一些对实时性要求极高的场景,如在线直播弹幕互动,低延迟的 WebSocket 能够让用户几乎实时看到其他观众发送的弹幕。
  • 双向通信:服务器和客户端可以随时互相发送数据,非常适合需要实时交互的场景。在在线教育平台中,教师和学生可以通过 WebSocket 进行实时的问答互动,提高教学效果。
  • 支持多种数据类型:可以传输文本、二进制数据等,灵活性高。例如在传输图片、音频等多媒体数据时,WebSocket 能够很好地胜任。

缺点

  • 复杂性较高:WebSocket 的实现相对复杂,需要处理连接管理、错误处理、重连机制等问题。在大型项目中,还需要考虑多用户连接的并发处理,以避免服务器性能瓶颈。
  • 兼容性问题:虽然现代浏览器普遍支持 WebSocket,但在一些老旧的浏览器或网络环境中可能会出现问题。为了解决兼容性问题,可以使用一些兼容性库,如 socket.io,它在底层对 WebSocket 进行了封装,并提供了额外的功能和更好的兼容性支持。

(五)WebSocket 的前端实现

在前端开发中,可以使用原生的 WebSocket API 来实现 WebSocket 通信。以下是一个简单的示例代码:


const socket = new WebSocket("wss://example.com/socket");socket.onopen = function (event) {console.log("WebSocket 已连接:", event);socket.send("客户端已连接");};socket.onmessage = function (event) {console.log("从服务器收到消息:", event.data);};socket.onerror = function (error) {console.log("WebSocket 发生错误:", error);};socket.onclose = function (event) {console.log("WebSocket 已关闭:", event);};

在实际项目中,为了更好地管理 WebSocket 连接,可以将其封装成一个单独的模块。例如:


class WebSocketService {constructor(url) {this.socket = new WebSocket(url);this.callbacks = {};this.socket.onopen = this.handleOpen.bind(this);this.socket.onmessage = this.handleMessage.bind(this);this.socket.onerror = this.handleError.bind(this);this.socket.onclose = this.handleClose.bind(this);}handleOpen(event) {console.log("WebSocket 已连接:", event);}handleMessage(event) {const data = JSON.parse(event.data);const callback = this.callbacks[data.type];if (callback) {callback(data);}}handleError(error) {console.log("WebSocket 发生错误:", error);}handleClose(event) {console.log("WebSocket 已关闭:", event);}sendMessage(message) {this.socket.send(JSON.stringify(message));}registerCallback(type, callback) {this.callbacks[type] = callback;}}// 使用示例const socketService = new WebSocketService("wss://example.com/socket");socketService.registerCallback("newMessage", (data) => {console.log("收到新消息:", data);});socketService.sendMessage({ type: "joinRoom", roomId: "123" });

二、Server-Sent Events (SSE):

(一)SSE 是什么?

Server-Sent Events (SSE) 是一种允许服务器向客户端推送实时数据的技术。与 WebSocket 不同,SSE 是单向的,只能由服务器向客户端发送数据,客户端无法主动向服务器发送数据。这种特性使得 SSE 在一些只需要服务器推送数据的场景中表现出色。

(二)SSE 的工作原理

  1. 建立连接:客户端通过在 HTML 中使用 <script> 标签或在 JavaScript 中使用 EventSource API 向服务器发起请求。服务器响应时,需要设置 Content-Type 为 text/event-stream,表示这是一个 SSE 连接。在实际开发中,服务器端需要配置合适的响应头,以确保 SSE 连接能够正常建立。
  1. 数据推送:服务器通过特定的格式向客户端发送数据。每次发送的数据以 data: 开头,以两个换行符结束。如果需要发送多个数据,可以连续发送多个这样的格式。例如:

data: {"message": "第一条消息"}data: {"message": "第二条消息"}
  1. 连接保持:SSE 连接会一直保持打开状态,直到客户端关闭或服务器主动断开。为了确保连接的稳定性,服务器可以定期发送一些心跳数据,防止连接被中间设备(如代理服务器)关闭。

(三)SSE 的应用场景

  • 新闻推送:例如新闻网站可以实时向用户推送最新的新闻标题。像 BBC 新闻网站就使用了 SSE 技术,当有新的新闻发布时,能够及时将新闻标题推送给用户,用户无需刷新页面即可获取最新信息。
  • 股票行情更新:服务器可以实时推送股票价格变化。在股票交易平台中,SSE 能够将股票的实时价格、涨跌幅等信息及时推送给投资者,方便投资者做出决策。
  • 日志流:服务器可以将日志信息实时推送给客户端进行展示。在一些运维监控系统中,通过 SSE 将服务器的日志信息实时推送给运维人员,便于及时发现和处理问题。

(四)SSE 的优缺点

优点

  • 简单易用:SSE 的实现相对简单,前端只需要使用 EventSource API,后端也较为容易实现。对于一些小型项目或对实时数据推送需求不太复杂的场景,SSE 是一个快速实现的选择。
  • 自动重连:浏览器会自动处理连接断开后的重连逻辑,开发者无需手动实现。这大大减轻了开发者的负担,提高了开发效率。
  • 兼容性较好:SSE 在现代浏览器中得到了较好的支持。与 WebSocket 相比,SSE 在兼容性方面表现更优,尤其是在一些对新技术支持不太友好的环境中。

缺点

  • 单向通信:只能由服务器向客户端发送数据,无法实现双向通信。这限制了 SSE 的应用场景,对于需要客户端和服务器双向交互的功能,SSE 无法满足需求。
  • 连接数量限制:由于 SSE 是基于 HTTP 的,服务器可能会受到连接数量的限制。在高并发场景下,过多的 SSE 连接可能会导致服务器性能下降,甚至出现连接超时等问题。

(五)SSE 的前端实现

以下是一个使用 EventSource API 的示例代码:


const eventSource = new EventSource("https://example.com/events");eventSource.onmessage = function (event) {console.log("从服务器收到消息:", event.data);};eventSource.onerror = function (error) {console.log("SSE 发生错误:", error);};eventSource.onopen = function (event) {console.log("SSE 已连接:", event);};

在实际应用中,有时需要处理自定义事件。SSE 支持自定义事件,只需要在服务器发送的数据中指定事件类型即可。例如:

服务器端发送数据:


event: customEventdata: {"message": "这是一个自定义事件消息"}

前端接收自定义事件:


const eventSource = new EventSource("https://example.com/events");eventSource.addEventListener('customEvent', function (event) {const data = JSON.parse(event.data);console.log("收到自定义事件消息:", data.message);});eventSource.onerror = function (error) {console.log("SSE 发生错误:", error);};eventSource.onopen = function (event) {console.log("SSE 已连接:", event);};

三、WebSocket 与 SSE 的对比

特性

WebSocket

Server-Sent Events (SSE)

通信方向

双向通信(客户端和服务器均可发送)

单向通信(仅服务器向客户端发送)

实现复杂度

较高(需要处理连接管理、错误处理等)

较低(前端使用 EventSource,后端简单)

兼容性

现代浏览器支持,但老旧浏览器可能不支持

现代浏览器支持较好

数据格式

支持文本和二进制数据

主要支持文本数据

自动重连

需要手动实现

浏览器自动处理

应用场景

实时聊天、在线游戏、实时数据可视化

新闻推送、股票行情、日志流

性能表现

在双向通信场景下性能更优,可处理复杂交互

在单向推送场景下性能良好,资源消耗较低

安全性

需开发者手动处理安全问题,如身份验证、数据加密

基于 HTTP,继承 HTTP 的安全特性,相对简单

四、选择合适的实时通信技术

选择 WebSocket 还是 SSE 取决于具体的应用场景和需求:

  • 如果需要双向通信(例如聊天应用或在线游戏),WebSocket 是更好的选择。同时,如果对数据传输的实时性和交互性要求较高,且能够接受相对复杂的开发和维护工作,WebSocket 更为合适。
  • 如果只需要服务器向客户端推送数据(例如新闻推送或股票行情),SSE 是一个更简单且高效的解决方案。此外,当项目对兼容性要求较高,且希望快速实现单向数据推送功能时,SSE 是首选。

在一些复杂的项目中,也可以考虑将 WebSocket 和 SSE 结合使用。例如,在一个实时监控系统中,对于需要双向交互的控制操作(如远程控制设备)使用 WebSocket,而对于实时数据的展示(如设备状态信息)使用 SSE,充分发挥两者的优势。

五、性能优化与安全防护

(一)性能优化

  1. WebSocket
  • 连接池:在服务器端建立连接池,复用已有的 WebSocket 连接,减少连接建立的开销。当有新的客户端请求连接时,优先从连接池中获取可用连接,提高连接效率。
  • 心跳机制:设置合适的心跳间隔,定期发送心跳数据,保持连接的活性,防止连接因长时间闲置而被关闭。同时,通过心跳机制可以及时检测到网络异常,进行相应的重连操作。
  • 数据压缩:如前文所述,对传输的数据进行压缩处理,减少网络传输的数据量,提高传输速度。可以使用 Gzip、Deflate 等压缩算法。
  1. SSE
  • 批量推送:在服务器端将多个数据合并成一个消息进行推送,减少推送次数,降低服务器和网络的压力。例如,将多条新闻标题合并成一个消息推送给客户端。
  • 缓存策略:合理设置缓存,对于一些不经常变化的数据,可以在客户端进行缓存,减少不必要的数据传输。当数据发生变化时,服务器再推送更新后的消息。

(二)安全防护

  1. WebSocket
  • 身份验证:在建立连接时,对客户端进行身份验证,确保只有合法的客户端能够连接到服务器。可以使用 JWT(JSON Web Token)等技术进行身份验证。
  • 数据加密:对传输的数据进行加密,防止数据被窃取或篡改。可以使用 TLS/SSL 加密协议,保证数据在传输过程中的安全性。
  • 防止跨站 WebSocket 劫持(CSWSH):采用类似防止 CSRF(跨站请求伪造)的方法,在请求中添加有效的令牌,验证请求的合法性。
  1. SSE
  • 同源策略:利用浏览器的同源策略,确保 SSE 连接只能从合法的源发起,防止恶意网站伪造 SSE 连接。
  • 数据过滤:在服务器端对发送的数据进行过滤和验证,防止恶意数据被推送到客户端。例如,对用户输入的数据进行合法性检查,防止 XSS(跨站脚本攻击)等安全问题。

相关文章:

Web 实时通信技术:WebSocket 与 Server-Sent Events (SSE) 深入解析

一、WebSocket&#xff1a; &#xff08;一&#xff09;WebSocket 是什么&#xff1f; WebSocket 是一种网络通信协议&#xff0c;它提供了一种在单个 TCP 连接上进行全双工通信的方式。与传统的 HTTP 请求 - 响应模型不同&#xff0c;WebSocket 允许服务器和客户端在连接建立…...

项目模拟实现消息队列第二天

消息应答的模式 1.自动应答: 消费者把这个消息取走了&#xff0c;就算是应答了&#xff08;相当于没有应答) 2.手动应答: basicAck方法属于手动应答(消费者需要主动调用这个api进行应答) 小结 1.需要实现生产者,broker server&#xff0c;消费者这三个部分的 2.针对生产者和消费…...

5.Redission

5.1 前文锁问题 基于 setnx 实现的分布式锁存在下面的问题&#xff1a; 重入问题&#xff1a;重入问题是指 获得锁的线程可以再次进入到相同的锁的代码块中&#xff0c;可重入锁的意义在于防止死锁&#xff0c;比如 HashTable 这样的代码中&#xff0c;他的方法都是使用 sync…...

c#数据结构 线性表篇 非常用线性集合总结

本人能力有限,使用了一些Ai的结论,如有不足还请斧正 目录 1.HashSet <> Dictionary 2.SortedSet <>提供升序方法的List 3.ArrayList<>List 4.BitArray <> Bit[] array 5.StringCollection <>List 6.StringDictionary<>Dictionary 1…...

dify 部署后docker 配置文件修改

1&#xff1a;修改 复制 ./dify/docker/.env.example ./dify/docker/.env 添加一下内容 # 启用自定义模型 CUSTOM_MODEL_ENABLEDtrue# 将OLLAMA_API_BASE_URL 改为宿主机的物理ip OLLAMA_API_BASE_URLhttp://192.168.72.8:11434# vllm 的 OPENAI的兼容 API 地址 CUSTOM_MODE…...

数据结构——排序(万字解说)初阶数据结构完

目录 1.排序 2.实现常见的排序算法 2.1 直接插入排序 ​编辑 2.2 希尔排序 2.3 直接选择排序 2.4 堆排序 2.5 冒泡排序 2.6 快速排序 2.6.1 递归版本 2.6.1.1 hoare版本 2.6.1.2 挖坑法 2.6.1.3 lomuto前后指针 2.6.1.4 时间复杂度 2.6.2 非递归版本 2.7 归并排序…...

SQLite3介绍与常用语句汇总

SQLite3简介 SQLite3是一款轻量级的、基于文件的开源关系型数据库引擎&#xff0c;由 D. Richard Hipp 于 2000 年首次发布。它遵循 SQL 标准&#xff0c;但与传统的数据库系统不同&#xff0c;SQLite 并不运行在独立的服务器进程中&#xff0c;而是作为一个嵌入式数据库引擎直…...

快速入门深度学习系列(3)----神经网络

本文只针对图进行解释重要内容 这就是入门所需要掌握的大部分内容 对于不懂的名词或概念 你可以及时去查 对于层数 标在上面 对于该层的第几个元素 标在下面 输入层算作第0层 对于第一层的w b 参数 维度如下w:4*3 b:4*1 这个叫做神经元 比如对于第一层的神经元 这里说的很…...

在线工具源码_字典查询_汉语词典_成语查询_择吉黄历等255个工具数百万数据 养站神器,安装教程

在线工具源码_字典查询_汉语词典_成语查询_择吉黄历等255个工具数百万数据 养站神器&#xff0c;安装教程 资源宝分享&#xff1a;https://www.httple.net/154301.html 一次性打包涵盖200个常用工具&#xff01;无论是日常的图片处理、文件格式转换&#xff0c;还是实用的时间…...

ORB-SLAM3和VINS-MONO的对比

直接给总结&#xff0c;整体上orbslam3&#xff08;仅考虑带imu&#xff09;在初始化阶段是松耦合&#xff0c;localmap和全局地图优化是紧耦合。而vins mono则是全程紧耦合。然后两者最大的区别就在于vins mono其实没有对地图点进行优化&#xff0c;为了轻量化&#xff0c;它一…...

大数据处理利器:Hadoop 入门指南

一、Hadoop 是什么&#xff1f;—— 分布式计算的基石 在大数据时代&#xff0c;处理海量数据需要强大的技术支撑&#xff0c;Hadoop 应运而生。Apache Hadoop 是一个开源的分布式计算框架&#xff0c;致力于为大规模数据集提供可靠、可扩展的分布式处理能力。其核心设计理念是…...

Docker容器网络架构深度解析与技术实践指南——基于Linux内核特性的企业级容器网络实现

第1章 容器网络基础架构 1 Linux网络命名空间实现原理 1.1内核级隔离机制深度解析 1.1.1进程隔离的底层实现 通过clone()系统调用创建新进程时&#xff0c;设置CLONE_NEWNET标志位将触发内核执行以下操作&#xff1a; 内核源码示例&#xff08;linux-6.8.0/kernel/fork.c&a…...

基于Kubernetes的Apache Pulsar云原生架构解析与集群部署指南(下)

文章目录 k8s安装部署Pulsar集群前期准备版本要求 安装 Pulsar Helm chart管理pulsarClustersBrokersTopic k8s安装部署Pulsar集群 前期准备 版本要求 Kubernetes 集群&#xff0c;版本 1.14 或更高版本Helm v3&#xff08;3.0.2 或更高版本&#xff09;数据持久化&#xff…...

IoTDB端边云同步技术的五大常见场景及简便使用方式

IoTDB端边云同步技术提供了一种高效、可靠的数据同步解决方案&#xff0c;通过简洁灵活的SQL操作和直观的配置方式&#xff0c;实现了数据在端、边、云之间的无缝流动。以下是IoTDB端边云同步的五大常见场景及其简便的使用方式。 一、基础数据同步 基础数据同步包括全量数据同…...

Linux 阻塞和非阻塞 I/O 简明指南

目录 声明 1. 阻塞和非阻塞简介 2. 等待队列 2.1 等待队列头 2.2 等待队列项 2.3 将队列项添加/移除等待队列头 2.4 等待唤醒 2.5 等待事件 3. 轮询 3.1 select函数 3.2 poll函数 3.3 epoll函数 4. Linux 驱动下的 poll 操作函数 声明 本博客所记录的关于正点原子…...

libtorch配置指南(包含Windows和Linux)

libtorch libtorch是pytorch的c库&#xff0c;提供了用于深度学习和张量计算的功能&#xff0c;允许开发者在c环境中使用pytorch的核心功能。特别是当一些pt模型无法转换到ncnn、mnn等模型时&#xff08;ncnn、mnn可能还不支持某些层&#xff09;&#xff0c;可以在libtorch直…...

Java开发经验——阿里巴巴编码规范经验总结2

摘要 这篇文章是关于Java开发中阿里巴巴编码规范的经验总结。它强调了避免使用Apache BeanUtils进行属性复制&#xff0c;因为它效率低下且类型转换不安全。推荐使用Spring BeanUtils、Hutool BeanUtil、MapStruct或手动赋值等替代方案。文章还指出不应在视图模板中加入复杂逻…...

机器人手臂“听不懂“指令?Ethercat转PROFINET网关妙解通信僵局

机器人手臂"听不懂"指令&#xff1f;Ethercat转PROFINET网关妙解产线通信僵局 协作机器人&#xff08;如KUKA iiWA&#xff09;使用EtherCAT控制&#xff0c;与Profinet主站&#xff08;如西门子840D CNC&#xff09;同步动作。 客户反馈&#xff1a;基于Profinet…...

深度学习 CNN

CNN 简介 什么是 CNN&#xff1f; 卷积神经网络&#xff08;Convolutional Neural Network&#xff09;是专为处理网格数据&#xff08;如图像&#xff09;设计的神经网络。核心组件&#xff1a; 卷积层 &#xff1a;提取局部特征&#xff08;如边缘、纹理&#xff09;通过卷…...

GrassRoot备份项目

Windows服务项目 Grass.cs using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Http.Headers; using System.Net.Http; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Time…...

iOS开发架构——MVC、MVP和MVVM对比

文章目录 前言MVC&#xff08;Model - View - Controller&#xff09;MVP&#xff08;Model - View - Presenter&#xff09;MVVM&#xff08;Model - View - ViewModel&#xff09; 前言 在 iOS 开发中&#xff0c;MVC、MVVM、和 MVP 是常见的三种架构模式&#xff0c;它们主…...

typecho中的Widget设计文档

组成系统的最基本元素 什么是Widget Widget是组成Typecho的最基本元素&#xff0c;除了已经抽象出来的类库外&#xff0c;其它几乎所有的功能都会通过Widget来完成。在实践中我们发现&#xff0c;在博客这种小型但很灵活的系统中实施一些大型框架的思想是不合适的&#xff0c…...

MySQL索引原理以及SQL优化(二)

目录 1. 索引与约束 1.1 索引是什么 1.2 索引的目的 1.3 索引分类 1.3.1 数据结构 1.3.2 物理存储 1.3.3 列属性 1.3.4 列的个数 1.4 主键的选择 1.5 索引使用场景 1.6 索引的底层实现 1.6.1 索引存储 1.6.2 页 1.6.3 B 树 1.6.4 B 树层高问题 1.6.5 自增 id 1.7 innod…...

MATLAB中矩阵和数组的区别

文章目录 前言环境配置1. 数据结构本质2. 运算规则&#xff08;1&#xff09;基本运算&#xff08;2&#xff09;特殊运算 3. 函数与操作4. 高维支持5. 创建方式 前言 在 MATLAB 中&#xff0c;矩阵&#xff08;Matrix&#xff09; 和 数组&#xff08;Array&#xff09; 的概…...

Desfire Ev1\Ev2\Ev3卡DES\3K3DES\AES加解密读写C#示例源码

本示例使用的发卡器&#xff1a;https://item.taobao.com/item.htm?spma21dvs.23580594.0.0.1d292c1bYhsS9c&ftt&id917152255720 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using S…...

MySQL核心内容【完结】

MySQL核心内容 文章目录 MySQL核心内容1.MySQL核心内容目录2.MySQL知识面扩展3.MySQL安装4.MySQL配置目录介绍Mysql配置远程ip连接 5.MySQL基础1.MySQL数据类型1.数值类型2.字符串类型3.日期和时间类型4.enum和set 2.MySQL运算符1.算数运算符2.逻辑运算符3.比较运算符 3.MySQL完…...

C++类和对象进阶 —— 与数据结构的结合

&#x1f381;个人主页&#xff1a;工藤新一 &#x1f50d;系列专栏&#xff1a;C面向对象&#xff08;类和对象篇&#xff09; &#x1f31f;心中的天空之城&#xff0c;终会照亮我前方的路 &#x1f389;欢迎大家点赞&#x1f44d;评论&#x1f4dd;收藏⭐文章 文章目录 […...

Django之账号登录及权限管理

账号登录及权限管理 目录 1.登录功能 2.退出登录 3.权限管理 4.代码展示合集 这篇文章, 会讲到如何实现账号登录。账号就是我们上一篇文章写的账号管理功能, 就使用那里面已经创建好的账号。这一次登录, 我们分为三种角色, 分别是员工, 领导, 管理员。不同的角色, 登录进去…...

从一城一云到AI CITY,智慧城市进入新阶段

AI将如何改变城市面貌&#xff1f;AI能否为城市创造新的商业价值&#xff1f;AI的落地应用将对日常生活有什么样的影响&#xff1f; 几乎在每一场和城市发展相关的论坛上&#xff0c;都会出现以上几个问题。城市既是AI技术创新融合应用的综合性载体&#xff0c;普罗大众对AI产…...

Oracle数据库DBF文件收缩

这两天新部署了一套系统&#xff0c;数据库结构保持不变&#xff0c;牵扯导出表结构还有函数&#xff0c;图省事就直接新建用户&#xff0c;还原数据库了。然后咔咔咔&#xff0c;一顿删除delete&#xff0c;truncate&#xff0c;发现要不就是表删了&#xff0c;还有num_rows&a…...