【问题标题】:How to copy a database with mysqldump and mysql in Python?如何在 Python 中使用 mysqldump 和 mysql 复制数据库?
【发布时间】:2014-12-03 01:47:53
【问题描述】:

我正在编写一个简单的 Python 脚本来复制 MySQL 数据库。我正在尝试根据以下 SO 问题及其答案复制数据库:“Copy/duplicate database without using mysqldump”、“python subprocess and mysqldump”和“Python subprocess, mysqldump and pipes”。但是,由于某些原因,我的脚本无法正常工作,因为表格和数据没有出现在我的新数据库中。

我可以从我的输出中看到 mysqldump 工作正常(我在输出中看到“Dump completed on...”),所以我认为 我的管道有问题

这是我的脚本:

#!/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 获取了复制数据库管道。起初我遇到了错误mysqldump: Couldn't find table: "|",就像that other question一样。所以现在我按照建议使用两个 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,但这也使我的脚本变得无响应。

同时在Popencall 中包含shell=True 也会导致脚本无响应。

但是,在命令提示符(我使用的是Windows 8.1)中输入命令确实有效,如下所示:

mysqldump -h localhost -P 3306 -u root -p mydb | mysql -h localhost -P 3306 -u root -p mydb2

它在不到三秒的时间内复制了我的小型测试数据库。

我希望我也可以让它在 Python 中工作。

【问题讨论】:

    标签: python mysql subprocess mysqldump pymysql


    【解决方案1】:

    我不知道你想要复制的pure Python的程度,但是你可以把整个管道操作委托给shell。

    subprocess.Popen('mysqldump -h localhost -P 3306 -u -root mydb | mysql -h localhost -P 3306 -u root mydb2', shell=True)
    

    这应该与您在 shell 上运行时的工作方式相同。

    【讨论】:

      【解决方案2】:

      我看到的一个问题是在这一行:

      p2 = Popen(args1, stdin=p1.stdout, stdout=PIPE, stderr=STDOUT)
      

      应该是:

      p2 = Popen(args2, stdin=p1.stdout, stdout=PIPE, stderr=STDOUT)
      

      (args1 被传递给第二个 proc,因此程序进行了两次转储和零恢复)

      【讨论】:

        【解决方案3】:

        当我尝试执行相同的任务时,我不断回到这篇文章,我突然想到这里没有响应的原因是你的 mysql 和 mysqldump 命令中的“-p”开关。 “-p”本身的意思是“提示输入密码”,所以子进程没有响应,因为它们正在等待密码输入。

        以防万一其他人遇到这个古老的线程并试图让它为自己工作,这对我来说是一个绊脚石。

        【讨论】:

          【解决方案4】:

          以下是在没有 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 会更简单。

          【讨论】:

          • 我不知道我们需要 .wait() :)
          • @matiu: mysqldump.wait() 被调用以避免创建僵尸。 mysqldump 进程本身在我们调用 .wait() 时已经完成。
          • 我很好奇:使用这种语法而不是像接受的答案中的内联管道有什么好处吗? (我猜除了可读性)
          • @olinox14:答案的最后一段解决了这个问题。
          猜你喜欢
          • 2010-09-06
          • 1970-01-01
          • 1970-01-01
          • 2011-05-25
          • 1970-01-01
          • 2011-04-28
          • 1970-01-01
          • 2014-01-30
          相关资源
          最近更新 更多