通过 python 恢复 SQL 服务器备份开始但未完成

Restoring SQL server backup via python starts but does not complete

我正在尝试使用 python 恢复 SQL 服务器备份。我有一个内置于 Tkinter 中的 UI,它接受文件路径和其他详细信息,如服务器名、数据库名等。为了测试,我只使用本地主机。我开发了两个文件。一个名为 tool.py 的文件具有 UI,另一个名为 Restorebackup.py 的文件具有恢复数据库的逻辑。当您 运行 tool.py 文件并按下开始按钮时,它会询问您要恢复的 .dat_bak 或 .bak 文件的文件路径。选择 .dat_bak 文件后,您等待一段时间,然后收到消息 "Backup is restored"。我转到 SQL Server Management Studio 并查看本地主机中的数据库。它显示备份正在用蓝色箭头恢复。不幸的是它永远不会完成并且永远停留在那里。当我通过硬编码文件路径和其他值来 运行 Restorebackup.py 时,它可以很好地恢复备份。不确定是什么问题

Restorebackup.py 文件

import pyodbc 
import os
#######################################################################################################################      
def restore_backup(selectedChoiceServer, selectedChoiceDatabase, selectedChoiceSchema, filePath):
    try:   
        driver= '{SQL Server}'        
        selectedChoiceServer="localhost"        
        db_environment= 'master'        
        username= 'sqlserverloginforlocalhost'        
        password='yourpassword'
        connectionString = (('DRIVER='+driver+';PORT=1433;SERVER='+selectedChoiceServer+';PORT=1443;DATABASE='+ db_environment +';UID='+username+';PWD='+ password)) 
        db_connection = pyodbc.connect(connectionString, autocommit=True)
        cursor = db_connection.cursor()      
        cursor.execute("""RESTORE FILELISTONLY FROM DISK = '"""+filePath+"""'""")
        dataset = cursor.fetchall()
        YourMDFLogicalName = dataset[0][0]
        YourLDFLogicalName = dataset[1][0]
        if not os.path.exists('c:/mybackup/backuptest'):
            os.mkdir('c:/mybackup/backuptest')
        db_connection = pyodbc.connect(connectionString, autocommit=True)
        sql = """  
        USE [master]
        RESTORE DATABASE [testdatabase] FROM  
        DISK = N'"""+filePath+"""' 
        WITH  FILE = 1
        ,RECOVERY
        ,  MOVE N'Service' TO N'C:/mybackup/backuptest/""" + YourMDFLogicalName + """.mdf'
        ,  MOVE N'Service_log' TO N'C:/mybackup/backuptest/""" + YourLDFLogicalName + """.ldf'
        ,  NOUNLOAD,  STATS = 5
        """ 
        cursor.execute(sql)
        db_connection.autocommit = False
        return 1
    except Exception as e:
        print('Some Error Occured, so backup was not restored')
        print('Error is :' + str(e))
        return str(e)
#######################################################################################################################      

tool.py 文件

from tkinter import messagebox 
from tkinter import filedialog
import unknown_support
from Restorebackup import restore_backup
import tkinter as Tk
from tkinter import *

def vp_start_gui():
    '''Starting point when module is the main routine.'''
    global val, w, root
    root = Tk() 
    top = Tool (root)
    unknown_support.init(root, top)
    root.mainloop()

def destroy_Tool():
    root.destroy()

class Tool:
    def StartButtonAction(self):
        self.Button1.config(state=DISABLED)
        selectedChoiceServer = self.Text3.get('1.0','end-1c')
        selectedChoiceDatabase = self.Text1.get('1.0','end-1c')
        selectedChoiceSchema =   self.Text2.get('1.0','end-1c')  
        root.fileName = filedialog.askopenfilename( filetypes = ( ("bak files", "*.dat_bak"),("All files","*.*") ) )
        #root.fileName = root.fileName.replace('/', '\')
        res = restore_backup(selectedChoiceServer, selectedChoiceDatabase, selectedChoiceSchema, root.fileName)
        if res == 1:
            messagebox.showinfo("Backup is restored", "Backup is restored")
        else:
            messagebox.showinfo("Error: ",res)

    def __init__(self, top=None):
        '''This class configures and populates the toplevel window.
           top is the toplevel containing window.'''
        top.geometry("600x450+761+233")
        top.title("Backup Restore Tool")
        top.configure(background="#d9d9d9")
        top.configure(highlightbackground="#d9d9d9")    
        top.configure(highlightcolor="black")

        self.choice = IntVar()
        self.databaseChoice = StringVar()

        self.Label1 = Label(top)
        self.Label1.place(relx=0.32, rely=0.38, height=26, width=58)
        self.Label1.configure(background="#d9d9d9")
        self.Label1.configure(disabledforeground="#a3a3a3")
        self.Label1.configure(foreground="#000000")
        self.Label1.configure(text='''Schema''')

        self.Label2 = Label(top)
        self.Label2.place(relx=0.3, rely=0.24, height=26, width=69)
        self.Label2.configure(background="#d9d9d9")
        self.Label2.configure(disabledforeground="#a3a3a3")
        self.Label2.configure(foreground="#000000")
        self.Label2.configure(text='''Database''')

        self.Label3 = Label(top)
        self.Label3.place(relx=0.3, rely=0.10, height=26, width=69)
        self.Label3.configure(background="#d9d9d9")
        self.Label3.configure(disabledforeground="#a3a3a3")
        self.Label3.configure(foreground="#000000")
        self.Label3.configure(text='''Server''')

        self.Text1 = Text(top)
        self.Text1.place(relx=0.45, rely=0.24, relheight=0.05, relwidth=0.39)
        self.Text1.configure(background="#ffffffffffff")
        self.Text1.configure(font="TkTextFont")
        self.Text1.configure(foreground="black")
        self.Text1.configure(highlightbackground="#d9d9d9")
        self.Text1.configure(highlightcolor="black")
        self.Text1.configure(insertbackground="black")
        self.Text1.configure(selectbackground="#c4c4c4")
        self.Text1.configure(selectforeground="black")
        self.Text1.configure(width=234)
        self.Text1.configure(wrap=WORD)


        self.Text2 = Text(top)
        self.Text2.place(relx=0.45, rely=0.38, relheight=0.05, relwidth=0.39)
        self.Text2.configure(background="white")
        self.Text2.configure(font="TkTextFont")
        self.Text2.configure(foreground="black")
        self.Text2.configure(highlightbackground="#d9d9d9")
        self.Text2.configure(highlightcolor="black")
        self.Text2.configure(insertbackground="black")
        self.Text2.configure(selectbackground="#c4c4c4")
        self.Text2.configure(selectforeground="black")
        self.Text2.configure(width=234)
        self.Text2.configure(wrap=WORD)

        self.Text3 = Text(top)
        self.Text3.place(relx=0.45, rely=0.10, relheight=0.05, relwidth=0.39)
        self.Text3.configure(background="white")
        self.Text3.configure(font="TkTextFont")
        self.Text3.configure(foreground="black")
        self.Text3.configure(highlightbackground="#d9d9d9")
        self.Text3.configure(highlightcolor="black")
        self.Text3.configure(insertbackground="black")
        self.Text3.configure(selectbackground="#c4c4c4")
        self.Text3.configure(selectforeground="black")
        self.Text3.configure(width=234)
        self.Text3.configure(wrap=WORD)


        self.Button1 = Button(top)
        self.Button1.place(relx=0.4, rely=0.58, height=33, width=186)
        self.Button1.configure(activebackground="#d9d9d9")
        self.Button1.configure(activeforeground="#000000")
        self.Button1.configure(background="#d9d9d9")
        self.Button1.configure(disabledforeground="#a3a3a3")
        self.Button1.configure(foreground="#000000")
        self.Button1.configure(highlightbackground="#d9d9d9")
        self.Button1.configure(highlightcolor="black")
        self.Button1.configure(pady="0")
        self.Button1.configure(text='''Start''')
        self.Button1.configure(width=186)
        self.Button1.configure(command = self.StartButtonAction)


        self.Button2 = Button(top)
        self.Button2.place(relx=0.4, rely=0.68, height=33, width=186)
        self.Button2.configure(activebackground="#d9d9d9")
        self.Button2.configure(activeforeground="#000000")
        self.Button2.configure(background="#d9d9d9")
        self.Button2.configure(disabledforeground="#a3a3a3")
        self.Button2.configure(foreground="#000000")
        self.Button2.configure(highlightbackground="#d9d9d9")
        self.Button2.configure(highlightcolor="black")
        self.Button2.configure(pady="0")
        self.Button2.configure(text='''Quit''')
        self.Button2.configure(width=186)
        self.Button2.configure(command = destroy_Tool)


if __name__ == '__main__':
    vp_start_gui()

我只是引入了一些延迟并进行了一些其他更改,这对我很有效。请参考代码如下

    restoreddatabase =  selectedChoiceSchema + '-' + strftime("%Y%m%d%H%M%S", gmtime()) +'import'
    connectionString = (('DRIVER='+driver+';PORT=1433;SERVER='+localserver+';PORT=1443;DATABASE='+ db_environment +';UID='+localusername+';PWD='+ password)) 
    db_connection = pyodbc.connect(connectionString, autocommit = True)
    cursor = db_connection.cursor()
    cursor.execute("""RESTORE FILELISTONLY FROM DISK = '"""+filePath+"""'""")
    dataset = cursor.fetchall()
    filenames = []
    for i in dataset:
        filedetails = {}
        #print(i[0])
        #print(i[1][::-1][:(i[1][::-1]).find('\')][::-1])
        filedetails['name'] = i[0]
        filedetails['withextension'] = i[1][::-1][:(i[1][::-1]).find('\')][::-1]
        filenames.append(filedetails)
    if not os.path.exists(rootfolder + '/'+ restoreddatabase):
        os.mkdir(rootfolder + '/'+ restoreddatabase)

    print(filePath)
    filePath = filePath.replace("/","\")
    rootfolder = rootfolder.replace("/","\")
    sql = """  
    USE [master]
    RESTORE DATABASE ["""+restoreddatabase+"""] FROM  
    DISK = N'"""+filePath+"""' 
    WITH  FILE = 1
    ,RECOVERY
    """ 
    for i in filenames:
        sql = sql + """, MOVE N'""" +i['name'] +"""' TO N'"""+ rootfolder +"""\"""+ restoreddatabase+"""\""" + i['withextension'] + """'"""

    sql = sql + """, NOUNLOAD,  STATS = 5
    """ 
    cursor.execute(sql)
    db_connection1 = pyodbc.connect(connectionString)
    cursor1 = db_connection1.cursor()
    database_restored_sql = """select top 1 * from msdb.dbo.restorehistory order by restore_date desc"""
    cursor1.execute(database_restored_sql)
    dataset = cursor1.fetchall()
    tquery = """        
    SELECT session_id as SPID, command, a.text AS Query, start_time, percent_complete, dateadd(second,estimated_completion_time/1000, getdate()) as estimated_completion_time FROM sys.dm_exec_requests r CROSS APPLY sys.dm_exec_sql_text(r.sql_handle) a WHERE r.command in ('BACKUP DATABASE','RESTORE DATABASE')       
    """
    print('Percentage Restored: ', end = '', flush = True)
    #sys.stdout.write('Percentage Restored: ')
    while restoreddatabase != dataset[0][2]:
        #print('in while')
        sleep(5)
        cursor1.execute(database_restored_sql)
        dataset = cursor1.fetchall()
        cursor1.execute(tquery)
        tdataset = cursor1.fetchall()
        if len(tdataset) > 0:
            if tdataset[0][4] > 99.99:
                print(str(tdataset[0][4])[0:3] + '%',end = ' ', flush = True)
                #sys.stdout.write(str(tdataset[0][4])[0:3] + '% ')
            else:
                print(str(tdataset[0][4])[0:2] + '% ',end = ' ', flush = True)
                #sys.stdout.write(str(tdataset[0][4])[0:2] + '% ')
    db_connection.autocommit = False