我正在编写一个简单的Python脚本来复制MySQL数据库。我正在尝试根据以下SO问题及其答案复制数据库:“Copy/duplicate database without using mysqldump”,“python subprocess and mysqldump”和“Python subprocess, mysqldump and pipes”。但是,由于某些原因我的脚本无法正常工作,因为表格和数据没有出现在我的新数据库中。
我可以从输出中看到mysqldump正常工作(我在输出中看到“Dump completed on ...”),所以我认为管道错误。< / p>
这是我的剧本:
#!/usr/bin/env python
import pymysql
from subprocess import Popen, PIPE, STDOUT
conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='', db='mydb')
cur = conn.cursor()
print("Attempting to create new database...")
try:
cur.execute("CREATE DATABASE mydb2")
print("Creating new database")
except Exception:
print("Database already exists")
print()
# close connection just to be sure
cur.close()
conn.close()
print("Trying to copy old database to new database...")
args1 = ["mysqldump", "-h", "localhost", "-P", "3306", "-u", "root", "-p", "mydb"]
args2 = ["mysql", "-h", "localhost", "-P", "3306", "-u", "root", "-p", "mydb2"]
p1 = Popen(args1, stdout=PIPE, stderr=STDOUT)
p2 = Popen(args1, stdin=p1.stdout, stdout=PIPE, stderr=STDOUT)
output = p2.communicate()
print("output:")
print(output)
print()
如您所见,我从this answer获取了复制数据库管道。最初,我在that other question中遇到了错误mysqldump: Couldn't find table: "|"
。所以现在我按照建议使用两个subprocess.Popen
调用,这解决了错误信息。
输出变量显示执行了mysqldump,但我没有看到有关mysql命令的任何内容。
我尝试使用p2.wait()
和p1.wait()
代替p2.communicate()
as suggested in one answer,但这只会让我的Python脚本无法响应。
我也尝试了以下内容:
output1 = p1.communicate()
output2 = p2.communicate()
但是output1和output2都显示相同的mysqldump输出。所以这只是一个愚蠢的事情我猜...
我还尝试使用subprocess.call
代替subprocess.Popen
,但这也使我的脚本无法响应。
在shell=True
或Popen
中同时包含call
也会导致脚本无法响应。
但是,它可以在命令提示符(我使用Windows 8.1)中键入命令,如下所示:
mysqldump -h localhost -P 3306 -u root -p mydb | mysql -h localhost -P 3306 -u root -p mydb2
它在不到三秒的时间内复制我的小型测试数据库。
我希望我也能在Python中使用它。
答案 0 :(得分:11)
我不知道您想要用于副本的纯Python 的程度,但您可以将整个管道操作委托给shell。
subprocess.Popen('mysqldump -h localhost -P 3306 -u -root mydb | mysql -h localhost -P 3306 -u root mydb2', shell=True)
这应该与在shell上运行时的工作方式相同。
答案 1 :(得分:2)
我看到的一个问题是这一行:
p2 = Popen(args1, stdin=p1.stdout, stdout=PIPE, stderr=STDOUT)
应该是:
p2 = Popen(args2, stdin=p1.stdout, stdout=PIPE, stderr=STDOUT)
(args1被传递给第二个proc,因此程序执行了两次转储和零恢复)
答案 2 :(得分:2)
当我尝试执行相同的任务时,我一直回到这篇文章,我突然想到这里没有响应的原因是您的 mysql 和 mysqldump 命令中的“-p”开关。 “-p”本身的意思是“提示输入密码”,因此子进程没有响应,因为它们正在等待密码输入。
以防万一其他人遇到这个古老的线程并试图让它为自己工作,这对我来说是一个绊脚石。
答案 3 :(得分:1)
以下是如何在没有shell的情况下运行mysqldump .. | mysql
管道:
#!/usr/bin/env python
from subprocess import Popen, PIPE
mysql = Popen("mysql -h localhost -P 3306 -u root -p mydb2".split(),
stdin=PIPE, stdout=PIPE)
mysqldump = Popen("mysqldump -h localhost -P 3306 -u root -p mydb".split(),
stdout=mysql.stdin)
mysql_stdout = mysql.communicate()[0]
mysqldump.wait()
请参阅How do I use subprocess.Popen to connect multiple processes by pipes?
如果您不需要传递需要复杂(可能是非便携式)转义的命令行参数,请捕获退出状态,stdout然后在这里使用shell更简单。