# 数据库备份与还原操作步骤(traffic_audit) > 整理于 2026-09-21。**备份 = 用 mysqldump 导出全库 sql**;**还原 = 把这个 sql 喂回 mysql**。 > 面向自己动手操作,命令都可以直接复制。 ## 0. 环境速查 | 项 | 值 | | --- | --- | | 服务端 | MySQL **8.0.29**,`127.0.0.1:3308` | | 库 / 账号 | 库 `traffic_audit`,账号 `root` / `123456` | | **导出工具** | `C:\Program Files\MySQL\MySQL Server 8.0\bin\mysqldump.exe`(**必须用 8.0 这个**,与服务端同版本) | | 日常查数客户端 | `D:\mysql\mysql-5.7.41-winx64\bin\mysql.exe` | **两个坑先记住** 1. 连接参数写 `--host=127.0.0.1`;写成 `-h127.0.0.1` 会被解析成主机名 `127`,直接连不上。 2. 输出文件用 `--result-file=` 让 mysqldump 自己写,不要用 `>` 重定向(中文路径 + PowerShell 引号容易翻车)。 --- ## 1. 备份(导出全库) ```powershell $ts = Get-Date -Format 'yyyyMMdd_HHmmss' $dir = 'D:\backup' # 路径不要留空格 New-Item -ItemType Directory -Force $dir | Out-Null $out = Join-Path $dir "traffic_audit_full_$ts.sql" & 'C:\Program Files\MySQL\MySQL Server 8.0\bin\mysqldump.exe' ` --host=127.0.0.1 --port=3308 --user=root --password=123456 ` --default-character-set=utf8mb4 ` --single-transaction --routines --triggers --events --hex-blob ` --databases traffic_audit ` --result-file=$out "exit=$LASTEXITCODE" Get-Item $out | Select-Object Name, Length, LastWriteTime ``` **成功判据**:`exit=0`,文件有几十 MB,且文件最后一行是 `-- Dump completed on ...`(没有就是中途断了)。 每个参数的作用: | 参数 | 作用 | | --- | --- | | `--host=127.0.0.1 --port=3308` | 本机服务端端口(见上「两个坑」) | | `--default-character-set=utf8mb4` | 中文不乱码,**必带** | | `--single-transaction` | 一致性快照,导出期间不锁表,别人照样能用系统 | | `--databases traffic_audit` | 连 `CREATE DATABASE` + `USE` 一起导 → 同事拿到**单个文件**就能整库还原 | | `--routines --triggers --events` | 本库目前没有这类对象(均为 0),带上只是防将来有 | | `--hex-blob` | 二进制列安全导出 | | `--result-file=...` | 直接写文件,绕开重定向的编码/引号问题 | > 只导某几张表:把 `--databases traffic_audit` 换成 `traffic_audit 表1 表2`(此时不带建库语句,只导结构和数据)。 --- ## 2. 验证「是不是真导全了」(三步,强度递增) 导出完**不要直接发人**,按下面三步核。 ### 第 1 步:结构齐不齐 ```powershell # 备份里的 CREATE TABLE 条数 (Select-String -Path $out -Pattern '^CREATE TABLE' -Encoding UTF8).Count # 库里实际表数 & 'D:\mysql\mysql-5.7.41-winx64\bin\mysql.exe' --host=127.0.0.1 --port=3308 --user=root --password=123456 ` -N -B -e "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema='traffic_audit';" ``` 两个数相等(本库是 **29**)才算结构齐。顺带确认没有 mysqldump 导不出来的对象: ```powershell & 'D:\mysql\mysql-5.7.41-winx64\bin\mysql.exe' --host=127.0.0.1 --port=3308 --user=root --password=123456 -e ` "SELECT (SELECT COUNT(*) FROM information_schema.views WHERE table_schema='traffic_audit') 视图, (SELECT COUNT(*) FROM information_schema.routines WHERE routine_schema='traffic_audit') 存储过程, (SELECT COUNT(*) FROM information_schema.triggers WHERE trigger_schema='traffic_audit') 触发器, (SELECT COUNT(*) FROM information_schema.events WHERE event_schema='traffic_audit') 事件;" ``` ### 第 2、3 步:还原到临时库,比行数 + 比内容 原理:把备份里的库名换成 `traffic_audit_vfy` 导进临时库,与源库逐表比对,比完删库。 ```powershell $root = 'D:\文档\ChatGPT\traffic-audit' $vfySql = "$root\_tmp\_verify.sql" # 2.1 换库名(用 28591 编码做「按字节替换」,不会动坏中文) $enc = [System.Text.Encoding]::GetEncoding(28591) $s = $enc.GetString([System.IO.File]::ReadAllBytes($out)) [System.IO.File]::WriteAllBytes($vfySql, $enc.GetBytes($s.Replace('`traffic_audit`', '`traffic_audit_vfy`'))) # 2.2 导入临时库(cmd 的 < 重定向最省事) $mysql = 'C:\Program Files\MySQL\MySQL Server 8.0\bin\mysql.exe' & $mysql --host=127.0.0.1 --port=3308 --user=root --password=123456 -e 'DROP DATABASE IF EXISTS traffic_audit_vfy;' cmd /c "`"$mysql`" --host=127.0.0.1 --port=3308 --user=root --password=123456 --default-character-set=utf8mb4 < `"$vfySql`"" # 2.3 逐表比行数 $tables = & $mysql --host=127.0.0.1 --port=3308 --user=root --password=123456 -N -B ` -e "SELECT table_name FROM information_schema.tables WHERE table_schema='traffic_audit' ORDER BY table_name;" & $mysql --host=127.0.0.1 --port=3308 --user=root --password=123456 -B -e (($tables | ForEach-Object { "SELECT '$_' 表,(SELECT COUNT(*) FROM traffic_audit.$_) 源库,(SELECT COUNT(*) FROM traffic_audit_vfy.$_) 备份" }) -join ' UNION ALL ') ``` 逐表两列数字一致 → 行数齐。 **最强的一步:比内容(SHA256)**。两张表行数一样、内容被改过,上面的方法看不出来,这个方法能: ```powershell $md = 'C:\Program Files\MySQL\MySQL Server 8.0\bin\mysqldump.exe' $common = '--host=127.0.0.1','--port=3308','--user=root','--password=123456','--default-character-set=utf8mb4', '--single-transaction','--no-create-info','--skip-comments','--order-by-primary','--hex-blob','--compact' & $md @common traffic_audit "--result-file=$root\_tmp\_cmp_src.sql" & $md @common traffic_audit_vfy "--result-file=$root\_tmp\_cmp_vfy.sql" (Get-FileHash "$root\_tmp\_cmp_src.sql").Hash -eq (Get-FileHash "$root\_tmp\_cmp_vfy.sql").Hash # True 才算全 ``` - `--order-by-primary`:按主键排序导出,保证两份文件行顺序一致,才能直接比哈希;本库 29 张表**都有主键**。 - 结果 `True` → 逐行内容完全一致。 **收尾**(验证完把临时库删掉,别留在服务器上): ```powershell & 'C:\Program Files\MySQL\MySQL Server 8.0\bin\mysql.exe' --host=127.0.0.1 --port=3308 --user=root --password=123456 ` -e 'DROP DATABASE IF EXISTS traffic_audit_vfy;' ``` --- ## 3. 还原(把备份装到这台或另一台机器) ```powershell cmd /c "`"C:\Program Files\MySQL\MySQL Server 8.0\bin\mysql.exe`" --host=127.0.0.1 --port=3308 --user=root --password=123456 --default-character-set=utf8mb4 < `"D:\backup\traffic_audit_full_20260921_103457.sql`"" ``` - 备份里含 `CREATE DATABASE`,**空环境**直接跑即可。 - 目标库**已有同名库**时:`CREATE DATABASE IF NOT EXISTS` 不报错,但后面 `CREATE TABLE` 会因表已存在而失败、半途中断。要么先 `DROP DATABASE traffic_audit;`,要么先确认是空环境。 - **不要**拿 `docs/init.sql` 去补已有数据的库:它带 `DROP TABLE`,是破坏性的。 --- ## 4. 常见问题 | 现象 | 原因 / 处理 | | --- | --- | | `mysqldump: [Warning] Using a password on the command line interface can be insecure.` | 只是警告,不影响结果;想消掉可用 `--defaults-extra-file` 放密码 | | 导入报 `Table 'xxx' already exists` | 目标库不是空的(见上) | | 导入报 `Unknown database` | 用 `--databases` 导出的备份不会出现;如果只导了表(没带建库语句),要自己先 `CREATE DATABASE traffic_audit` | | 中文变问号/乱码 | 导出、导入两头都要 `--default-character-set=utf8mb4` | | 备份文件只有几百 KB | 十有八九是 `--databases` 写错库名或连接失败,看退出码和文件末尾有没有 `Dump completed` | | 想只备份一张表 | `mysqldump ... traffic_audit 表名 --result-file=...` | --- ## 5. 本次实测记录(2026-09-21) - 备份文件:`_给同事_2026-09-21\traffic_audit_full_20260921.sql`,52,030,977 字节(约 49.6 MB),导出时间 10:34:57。 - SHA256:`832B518F45313420...`(完整值见 `_给同事_2026-09-21\还原说明_2026-09-21.md`)。 - 验证结果:29/29 张表结构齐、行数一致(合计 128,962 行)、`CHECKSUM TABLE` 一致、逐行 SHA256 一致。 - **经验教训**:10:17 先导了一份,10:34 复查发现源库已被改动(`investment_system` 148→277、`audit_result` 3393→3421、`import_batch` 417→419),旧备份已过期。 → **备份是某一时刻的快照**;只要之后还在往系统里导数据、跑审核,备份就旧了。交付/归档前**最后再导一次**。 > 判断备份新旧的最快办法:看文件名里的时间戳,与 `import_batch` 的 `MAX(created_at)` 比一下。