通过python恢复SQL Server备份已启动但未完成

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了通过python恢复SQL Server备份已启动但未完成相关的知识,希望对你有一定的参考价值。

我正在尝试使用python恢复SQL Server备份。我在Tkinter中建立了一个UI,它接受文件路径和其他详细信息,例如服务器名,数据库名等。为进行测试,我仅使用localhost。我已经开发了两个文件。一个名为tool.py的用户界面,而另一个名为Restorebackup.py的文件,该文件具有还原数据库的逻辑。当您运行tool.py文件并按开始按钮时,它会询问您要还原的.dat_bak或.bak文件的文件路径。选择.dat_bak文件后,您需要等待一段时间,并且会收到“还原备份”的消息。我转到SQL Server Management Studio,并查看localhost中的数据库。它显示备份正在用蓝色箭头还原。不幸的是,它永远不会完成,并永远停留在那里。当我通过对文件路径和其他值进行硬编码来运行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

以上是关于通过python恢复SQL Server备份已启动但未完成的主要内容,如果未能解决你的问题,请参考以下文章

sql server 备份恢复效率

SQL Server 2008每日备份

《SQL Server企业级平台管理实践》读书笔记——几个系统库的备份与恢复

从损坏的 SQL Server 数据库中恢复事务日志

SQL Server备份恢复维护计划实现备份:每周数据库完整备份每天差异备份每小时日志备份

sql server怎么收缩日志