Ожидание завершения восстановления БД с использованием sqlalchemy на SQL Server 2008 - PullRequest
3 голосов
/ 23 ноября 2010

Я пытаюсь автоматизировать восстановление БД во время разработки, используя TSQL на SQL Server 2008, используя sqlalchemy с pyodbc в качестве транспорта.

Я выполняю команду:

"" "СОЗДАТЬ БАЗУ ДАННЫХ

восстановить базу данных dbname ОТ ДИСКА = 'C: \ Backups \ dbname.bak' С ЗАМЕНАМИ, ПЕРЕМЕЩАТЬ 'dbname_data' В 'C: \ Базы данных \ dbname_data.mdf', MOVE 'dbname_log'TO' C: \ Databases \ dbname_log.ldf '"" "

К сожалению, в SQL Management Studio после запуска кода я вижу, что БД остается в состоянии« Восстановление ... ».

Если я восстановлю через управление студией, все заработает.Если я использую подпроцесс для вызова «sqlcmd», это работает.У pymssql есть проблемы с аутентификацией, и он даже не заходит так далеко.

Что может быть не так?

Ответы [ 4 ]

3 голосов
/ 08 февраля 2013

Операторы BACKUP и RESTORE выполняются асинхронно, поэтому они не завершаются до перехода к остальной части кода.

Использование оператора while, как описано в http://ryepup.unwashedmeme.com/blog/2010/08/26/making-sql-server-backups-using-python-and-pyodbc/, решило это для меня:

# setup your DB connection, cursor, etc
cur.execute('BACKUP DATABASE ? TO DISK=?', 
            ['test', r'd:\temp\test.bak'])
while cur.nextset():
    pass
2 голосов
/ 24 ноября 2010

Невозможно воспроизвести проблему, восстанавливающую непосредственно из pyodbc (без sqlalchemy), выполнив следующее:

connection = pyodbc.connect(connection_string) # ensure autocommit is set to `True` in connection string
cursor = connection.cursor()
affected = cursor.execute("""CREATE DATABASE test
RESTORE DATABASE test FROM DISK = 'D:\\test.bak' WITH REPLACE, MOVE 'test_data' TO 'D:\\test_data.mdf', MOVE 'test_log' to 'D:\\test_log.ldf' """)
while cursor.nextset():
    pass

Некоторые вопросы, требующие уточнения:

  • Какой код используется для восстановления с использованием sqlalchemy?
  • Какая версия драйвера ODBC для SQL Server используется?
  • Есть ли в журнале SQL Server какие-либо сообщения, связанные с восстановлением?

Спасибо geographika за Cursor.nextset () пример!

0 голосов
/ 20 января 2018

Для пользователей SQL Alchemy, и спасибо географии за ответ: в итоге я использовал «сырое» DBAPI соединение из пула соединений.

Это в точности как решение географии, но с несколькими дополнительными частями:

import sqlalchemy as sa
driver = 'SQL+Server'
name = 'servername'
sql_engine_str = 'mssql+pyodbc://'\
                     + name\
                     + '/'\
                     + 'master'\
                     + '?driver='\
                     + driver
engine = sa.create_engine(sql_engine_str, connect_args={'autocommit': True})

connection = engine.raw_connection()
try:
  cursor = connection.cursor()
  sql_cmd = """
        RESTORE DATABASE [test]
        FROM DISK = N'...\\test.bak'
        WITH FILE = 1,
         MOVE N'test'
         TO N'...\\test_Primary.mdf',
         MOVE N'test_log'
         TO N'...\\test_log.ldf',
         RECOVERY,
         NOUNLOAD,
         STATS = 5,
         REPLACE
        """
  cursor.execute(sql_cmd)
  while cursor.nextset():
       pass
except Exception as e:
  logger.error(str(e), exc_info=True)
0 голосов
/ 09 января 2014

Пять вещей решили мою проблему с одинаковыми симптомами.

  1. Обнаружено, что мой файл test.bak содержал неправильные файлы mdf и ldf:

    >>> cursor.execute(r"RESTORE FILELISTONLY FROM DISK = 'test.bak'").fetchall()    
    [(u'WRONGNAME', u'C:\\Program Files\\Microsoft SQL ...),
    (u'WRONGNAME_log', u'C:\\Program Files\\Microsoft SQL ...)]
    
  2. Создал новый файл bak и убедился, чтодля установки опции copy-only backup

  3. Установите опцию автоматической фиксации для моего соединения.

    connection = pyodbc.connect(connection_string, autocommit=True)
    
  4. Использовал connection.cursor только дляодна команда RESTORE и ничего больше

  5. Исправлено test_data MOVE в test в моей команде RESTORE (любезно @beargle).

    affected = cursor.execute("""RESTORE DATABASE test FROM DISK = 'test.bak' WITH REPLACE, MOVE 'test' TO 'C:\\test.mdf', MOVE 'test_log' to 'C:\\test_log.ldf' """)
    
...