你的数据库被删了,现在怎么办?

刚泡好咖啡,网站突然打不开,后台一片空白——你手一抖点开服务器,发现数据库目录空了。
不是幻觉,是真的没了。订单、用户、文章……全在那一片寂静里消失了。
别关页面,先深呼吸三次。只要备份还在,这事就能扳回来。下面每一步,我都按你正手忙脚乱时最需要的顺序写。

恢复前,你必须立刻做的3件事

马上停掉所有写操作。
关网站、停应用、杀掉 MySQL 或 PostgreSQL 进程。哪怕只多跑一秒,都可能把残留的数据块彻底覆盖掉。

快速判断删到哪一步了。
是某张表被 DROP TABLE?整个库被 DROP DATABASE?还是磁盘直接挂了?翻一下 MySQL 的 error log 或系统操作记录(比如 ~/.bash_history),看最后一笔可疑命令是什么时候执行的。这决定了你是秒级恢复,还是得翻日志一点点捞。

立刻摸清备份在哪、能不能用。
打开你的对象存储控制台(比如阿里云 OSS、腾讯云 COS)、NAS 共享目录,或者另一台备用服务器,找到最近一次的备份文件。确认两件事:文件没损坏(大小明显异常就危险)、时间没过期(超过48小时的备份,先标个“应急用”,别当主力)。顺手也查查 binlog 开没开、有没有被自动清理。

一个真实教训:有位朋友在测试环境连错库,手抖敲了 DROP DATABASE prod;。他第一反应不是骂自己,而是立刻在 Nginx 层加了维护页,同时禁用数据库账号。等冷静下来翻 binlog 归档,发现事故前2分钟刚做过全量备份,后面的所有变更都在日志里——最后数据一比特没丢。

你的备份真的能用吗?验证策略

备份文件躺在硬盘上,不等于它能救你命。
真要救急,得先在沙盒里跑一遍。
拿你本地电脑装个 Docker,起个干净 MySQL 容器,把备份倒进去,看看用户表、订单表的数据是不是完整,主键有没有断号,时间字段有没有全变成 0000-00-00

别光看文件大小,要动手验“体温”。
SQL 备份?用 head -n 20 backup.sql 瞅一眼开头是不是 CREATE DATABASE,再 tail -n 10 backup.sql 看结尾有没有 -- Dump completed。物理备份(比如 XtraBackup)?跑一遍 xtrabackup --check,看校验值对不对。
另外提醒一句:mysqldump 默认不导用户权限和存储过程。如果你的业务依赖自定义函数或特殊权限,现在就去补一句 --routines --events --users 重备一次。

把“恢复演练”塞进月度运维清单。
很多团队备份脚本跑了三年,第一次恢复才发现路径写错了、压缩包根本解不开、备份里漏了 information_schema。建议每季度挑个周五下午,花40分钟走一遍完整流程——就当给系统做个体检。

从逻辑备份恢复:SQL文件还原详解

逻辑备份最常见,就是 .sql 文件。恢复三步走:

  1. 登录 MySQL,建个空库:CREATE DATABASE new_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
  2. 导入:mysql -u root -p new_db < /path/to/backup.sql
  3. 导完别急着上线,先连上去 SELECT COUNT(*) FROM users; 看看行数对不对。

大文件别硬扛,加点小技巧。
如果备份几百MB,加个进度条心里踏实:pv backup.sql | mysql -u root -p new_db(没装 pvbrew install pvapt install pv)。
压缩包?直接管道解压导入:zcat backup.sql.gz | mysql -u root -p new_db

两个坑,踩过才懂。

  • 字符集不一致会炸出一堆问号。导出时用 --default-character-set=utf8mb4,导入时也保持一致;
  • 权限和函数得单独处理。下次备份加上 --all-databases --routines --events --users,一劳永逸。

从物理备份恢复:全量与增量结合

物理备份快,但门槛高。常用工具是 Percona XtraBackup(MySQL)或 pg_basebackup(PostgreSQL)。

全量恢复四步法(以 XtraBackup 为例):

  1. 准备备份:xtrabackup --prepare --target-dir=/backup/full/
  2. 停服务:systemctl stop mysql
  3. 清空原数据目录(⚠️先备份旧目录!):mv /var/lib/mysql /var/lib/mysql.bak
  4. 复制恢复:xtrabackup --copy-back --target-dir=/backup/full/,改属主 chown -R mysql:mysql /var/lib/mysql,再启动。

想恢复到故障前一秒?得靠增量+binlog。
先按上面步骤恢复全量备份;再按时间顺序 --prepare--apply-log 所有增量包;最后用 mysqlbinlog --start-datetime="2024-05-20 14:22:00" --stop-datetime="2024-05-20 14:23:15" 截取日志,过滤掉 DROP 那几行,只重放 INSERT/UPDATE

没有备份?最后的救命稻草

先说句实话:没备份还想全量恢复,概率很低。但还有三根线头可抓——

第一根:binlog 还活着吗?
执行 mysql -u root -p -e "SHOW BINARY LOGS;"。如果列表里还有 mysql-bin.000012 这种文件,立刻用 mysqlbinlog mysql-bin.000012 > binlog.sql 导出来,手动删掉里面的 DROP 语句,再导入。

第二根:磁盘文件没被覆盖,就还有戏。
立刻卸载磁盘(umount /dev/sdb1),用 extundelete(CentOS/Ubuntu)或 photorec(跨平台)扫描。重点找 .ibd 文件(InnoDB 表空间)或整个 mysql/ 目录。恢复后,在新实例里用 ALTER TABLE xxx IMPORT TABLESPACE 挂载。

第三根:找人帮忙。
如果以上全失效,联系你云厂商的技术支持(阿里云、腾讯云都有付费数据库救援服务),或者熟识的 DBA。别自己瞎试 debugfs,越动越糟。

核心原则只有一条:从现在起,禁止往这块盘写任何新数据。

今天就能执行的备份与恢复检查清单

别收藏吃灰,现在就打开终端,按顺序做:

  1. 定位备份ls -lh /backup/mysql/ 或打开你的 OSS 控制台,找到最新那个 .sql.xbstream 文件,记下路径和修改时间;
  2. 本地测恢复:Docker 跑起来 docker run --name mysql-test -e MYSQL_ROOT_PASSWORD=123 -d -p 3307:3306 mysql:8.0,然后 mysql -h 127.0.0.1 -P 3307 -u root -p123 test_db < backup.sql
  3. 查 crontabcrontab -l | grep mysqldump,再看下日志 tail -20 /var/log/mysqldump.log,确认最近一次有没有 completed successfully
  4. 扫一眼备份内容zcat backup.sql.gz | head -n 50 | grep "CREATE TABLE users",看到建表语句才算过关;
  5. 存好恢复命令:把这行贴进你常用的笔记软件(飞书文档/语雀/Notion):
    mysql -u root -p your_db_name < /backup/mysql/latest.sql
    
    下次手抖时,复制粘贴就行。

做完这五件事,你心里那块石头就落地了。
备份不是存了个文件,是你亲手验证过“我能把它变回来”的底气。
现在,关掉这篇文章,打开终端。