mysqldump备份卡住或锁表是因未加--single-transaction:innodb表默认触发flush tables with read lock导致写入阻塞;该参数利用mvcc快照避免锁表,但要求全库为innodb引擎,混合引擎时自动退化为加锁模式。

mysqldump 备份卡住或锁表,是因为没加 --single-transaction
生产环境跑 mysqldump 时,如果表还在写入,又没加事务隔离参数,InnoDB 表默认会触发全局读锁(FLUSH TABLES WITH READ LOCK),导致写入阻塞、业务超时。这不是 bug,是 mysqldump 的默认安全策略——它想保证一致性,但代价是停写。
对 InnoDB 表,--single-transaction 是关键:它利用 MVCC 在事务快照里拉取数据,全程不锁表。但注意前提:必须确保所有表都是 InnoDB 引擎,混合引擎(比如有 MyISAM 表)时该参数自动失效,mysqldump 会悄悄退回到加锁模式。
- 检查引擎:
SELECT table_name, engine FROM information_schema.tables WHERE table_schema = 'your_db'; - 如果存在 MyISAM 表,要么先转成 InnoDB(
ALTER TABLE t ENGINE=InnoDB;),要么改用--lock-tables=false+--skip-lock-tables(但一致性无法保障) -
--single-transaction和--lock-tables互斥,后者显式设为false才生效
备份慢、IO 高,--quick 和 --compress 得一起用
默认情况下,mysqldump 把整张表查出来再拼 SQL,大表容易 OOM 或拖慢数据库;网络传输阶段明文 SQL 体积大,加重带宽和磁盘压力。
--quick 让 mysqldump 逐行 fetch,避免客户端内存暴涨;--compress 启用 MySQL 协议级压缩(不是 gzip),能减小 30%~60% 传输量,尤其对文本字段多的库效果明显。
- 这两个参数不冲突,建议固定组合使用:
mysqldump --single-transaction --quick --compress ... -
--compress需服务端也开启have_compression=ON(MySQL 5.7+ 默认开),否则静默忽略 - 别混淆
--compress和外部管道压缩(如| gzip):前者压协议包,后者压最终 SQL 文件,两者可叠加,但顺序很重要——先协议压缩再管道压缩更省资源
还原失败报错 ERROR 1067 (42000): Invalid default value for 'xxx'
这是 MySQL 5.7+ 严格模式(sql_mode=STRICT_TRANS_TABLES)和低版本 dump 不兼容的典型表现。老库导出的 0000-00-00 日期、空字符串默认值,在新实例上被拒。
根本解法不是关严格模式(生产不推荐),而是导出时主动适配目标环境:
- 加
--compatible=mysql40或--compatible=ansi可降级语法,但会牺牲部分特性(如分区表注释丢失) - 更稳妥的是用
--skip-create-options跳过建表语句里的 ENGINE/ROW_FORMAT 等可能引发冲突的选项,自己手写 CREATE 语句控制细节 - 若必须保留原建表结构,还原前临时设置:
SET sql_mode='';(仅当前 session,不影响全局)
备份文件里没有 CREATE DATABASE,还原时得手动建库
mysqldump db1 tb1 这种只指定库名+表名的写法,默认不输出 CREATE DATABASE 和 USE,还原时如果目标库不存在,直接报错 ERROR 1049 (42000): Unknown database。
是否加库级语句,取决于你用什么方式调用:
- 全库备份(
mysqldump --all-databases或mysqldump db1)会自带CREATE DATABASE IF NOT EXISTS - 单表备份(
mysqldump db1 t1)不会——它假设你已准备好库环境 - 想强制加
CREATE DATABASE,可用--databases参数:即mysqldump --databases db1 t1,注意这里db1是作为数据库名传入,不是表名
线上脚本里漏掉这个细节,半夜恢复就只能干瞪眼。











