You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python调用subprocess.Popen执行MySQL迁移时wait方法长期阻塞无法退出

问题修复方案

问题根源

  • 进程等待顺序错误:当前代码先调用mysql.communicate()再等待mysqldump退出,管道上下游等待顺序颠倒,导致下游mysql进程一直等待上游输入,无法正常退出。
  • 管道文件描述符未正确关闭:mysqldump执行完成输出所有内容后,中间sed进程的stdin没有收到EOF,sed不会主动退出,进而mysql的stdin也一直处于打开状态,mysql进程会永久等待输入,触发死锁。
  • 强制中断触发的SQL语法报错是终止时mysql接收到了不完整的SQL片段导致的,不属于代码逻辑本身的问题。

修复代码

import sys
import os
from subprocess import Popen, PIPE, STDOUT
import shlex

# Transfer Database
print('Transferring from ' + mysql_source_database)
# 改用shlex.split避免账号、库名含特殊字符时拆分错误
mysql = Popen(shlex.split(f"mysql -h {mysql_dest_host} -P 3306 -u {mysql_dest_username} -p{mysql_dest_pw} {mysql_dest_database}"), stdin=PIPE, stdout=PIPE, stderr=STDOUT)
dbnamerewrite = Popen(shlex.split(f"sed s/{mysql_source_database}/{mysql_dest_database}/g"), stdin=PIPE, stdout=mysql.stdin)
mysqldump = Popen(shlex.split(f"mysqldump --set-gtid-purged=OFF --column-statistics=0 -h {mysql_source_host} -P 3306 -u {mysql_source_username} -p{mysql_source_pw} {mysql_source_database}"), stdout=dbnamerewrite.stdin)

# 按上游到下游顺序等待进程退出,主动关闭对应管道避免死锁
mysqldump.wait()
dbnamerewrite.stdin.close()
dbnamerewrite.wait()
mysql.stdin.close()
mysql_stdout = mysql.communicate()[0]

# 可选:增加退出码检查判断执行结果
if mysqldump.returncode != 0:
    print(f"mysqldump执行失败,退出码:{mysqldump.returncode}")
if dbnamerewrite.returncode !=0:
    print(f"sed执行失败,退出码:{dbnamerewrite.returncode}")
if mysql.returncode !=0:
    print(f"mysql导入失败,退出码:{mysql.returncode},输出:{mysql_stdout.decode('utf-8', errors='ignore')}")

修复逻辑说明

  • 调整等待顺序:先等最上游的mysqldump执行完成,确认所有备份内容已经输出到sed的输入管道
  • 主动关闭管道:mysqldump退出后主动关闭sed的stdin,让sed收到EOF后处理完剩余内容退出,之后关闭mysql的stdin,让mysql收到EOF后开始执行所有导入逻辑
  • 最后调用mysql的communicate读取所有输出,等待mysql进程正常退出

内容的提问来源于stack exchange,提问作者Krobar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.11 23:24:00