ThinkPHP数据库备份需手动构造SQL,先确认Db::query()可执行原生语句;导出分SHOW CREATE TABLE和SELECT两步,补分号、转INSERT、分块查询防内存溢出;字符集须全链路设为utf8mb4;禁用mysqldump,改用PHP可控拼接。

备份前先确认 think\facade\Db 能否正常执行原生 SQL
ThinkPHP 的数据库备份不是靠框架封装好的“一键备份”功能,而是依赖你手动构造 SHOW CREATE TABLE 和 SELECT 语句,再拼成 SQL 文件。如果连 Db::query() 执行建表语句都报错,后续所有操作都会失败。
常见错误现象:SQLSTATE[HY000]: General error: 1046 No database selected,说明配置里没指定 database 名,或连接时没自动 USE 切库。
- 检查
config/database.php中'database'配置项是否为空字符串或拼写错误 - 用
Db::execute('USE `your_db_name`')强制切库(仅调试用) - 避免在多应用模式下误用了默认连接名,确认
Db::connect('mysql')指向的是目标库
导出单表结构和数据必须分两步:先 SHOW CREATE TABLE,再 SELECT * FROM
直接 SELECT * INTO OUTFILE 在 ThinkPHP 里不可行——MySQL 服务端限制、PHP 进程无文件写权限、且不兼容所有部署环境(比如容器或共享主机)。稳妥做法是 PHP 拼接标准 SQL 格式文本。
关键细节:
立即学习“PHP免费学习笔记(深入)”;
-
SHOW CREATE TABLE `user`返回两列:Table和Create Table,取第二列即可,注意末尾缺分号,要手动补上 -
SELECT * FROM user查出数据后,需逐行转成INSERT INTO `user` VALUES (...),字段名不用引号,但字符串值必须用单引号 +addslashes()或mysqli_real_escape_string() - 大表务必加
chunk(500),否则内存爆掉,Db::table('user')->chunk(500, function($rows){...})
生成的 .sql 文件中文乱码?重点看三处字符集
不是简单地在文件头写 SET NAMES utf8mb4; 就能解决。乱码往往发生在三个环节:数据库连接、查询结果编码、文件保存编码。
- 确认
config/database.php中'charset'是'utf8mb4',不是'utf8'(后者不支持 emoji) -
Db::query("SHOW VARIABLES LIKE 'character_set_client'")查连接实际生效的 client 字符集,若为latin1,说明 DSN 缺少;charset=utf8mb4 - 写文件时用
file_put_contents($path, $content, FILE_APPEND | LOCK_EX),别用fopen+fwrite忘记设置bom或编码转换
线上环境慎用 mysqldump 命令调用
有人图省事在控制器里 exec('mysqldump -u... > backup.sql'),看似快,实则埋雷。
- PHP 进程可能被禁用
exec、shell_exec(尤其宝塔、cPanel 默认关掉) - 路径权限问题:PHP 用户(如
www)不一定有权限读写 MySQL 数据目录,也未必能访问mysqldump二进制文件(常在/usr/bin/,但容器里可能没有) - 超时风险:大库导出卡住,导致请求 504,而 PHP 层完全感知不到进程状态
- 更稳的做法:用 ThinkPHP 自己查、自己拼、自己写,可控性强,还能加进度日志和断点续传逻辑
真正麻烦的不是语法,是备份过程中对连接稳定性、内存占用、字符边界、权限隔离的持续校验——这些没法靠一个函数调用绕过去。



















