Пакетный файл для резервного копирования и обновления SQL Server DB

Это мой первый пакетный файл Windows. Скрипт в основном проходит этот основной поток задач, чтобы обновить некоторые конкретные базы данных SQL Server до новой версии DB:

  1. Резервное копирование всех SQL-серверов SQL, которые будут обновлены.
  2. Перейдите к последней версии и примените любые исправления в последнюю минуту к этим БД.
  3. Обработка ошибок выполняется, когда процесс завершается с ошибкой в ​​любой момент, отбрасывая все БД до их начальной версии (до обновления).

Буду признателен за ваши отзывы:

  • Какие части кода могут быть улучшены в целом (исправить некоторые плохие практики, улучшить хрупкий код и т. д.).
  • Как лучше организовать (комментарии, разделение разделов и т. д.) кода и сделать его более понятным (для удобства обслуживания).
  • Любые другие аспекты, которые, по вашему мнению, должны быть улучшены, особенно в отношении стиля и стандартизации пакетного кодирования.

Вот полный код:

:: MAIN SCRIPT OPTIONS
@echo off
setlocal EnableDelayedExpansion

:: ------------------------------------------------------------------------------------------------
:: PARAMETERS (ADJUST TO SPECIFIC ENVIRONMENT)

:: SQL Server: instance holding the DBs
set serverName=SERVER\SQLEXPRESS
:: SQL Server: user name and user password for performing the upgrade
set sqlUser=%1
set sqlPwd=%2
:: SQL Server: comma separated list of DBs in this server instance that should be upgraded
set sqlDBs=DB1,DB2

:: DB version: current version to be upgraded
set currentVersion=4.3.0
:: DB version: target version to upgrade to
set targetVersion=4.4.0
:: DB version: scripts (if multiple, quote and separate with commas) to run before applying the upgrade (leave blank if none is needed)
set prePatchScripts=
:: DB version: scripts (if multiple, quote and separate with commas) to run after applying the upgrade (leave blank if none is needed)
set postPatchScripts="Script1.sql,Script2.sql"

:: ------------------------------------------------------------------------------------------------
:: CALCULATED VARIABLES (DO NOT MODIFY)

:: Folders: scripts working directory
set workingDir=%~dp0
:: Folders: path to store the DB backups
set backupDir=%workingDir%Backups\
:: Folders: path where upgrade and patch scripts will be found
set scriptsDir=%workingDir%Scripts\

:: File names: name of the upgrade script to be applied
set updateScript=Update_SCM_%currentVersion%_a_%targetVersion%.sql
:: File names: name of the log file where messages will be written
set logFile=log.txt

:: ------------------------------------------------------------------------------------------------
:: BACK UP EVERY DB IN THE SERVER
call :echo_header "Backing up all DBs in the server"
for /d %%a in (%sqlDBs%) do (
    echo Backing up database: %%a to %backupDir%%%a.bak
    sqlcmd -b -S !serverName! -U !sqlUser! -P !sqlPwd! -Q "backup database [%%a] to Disk='!backupDir!%%a.bak' with init"
    echo.
) 

:: ------------------------------------------------------------------------------------------------
:: UPDATE AND PATCH EACH DB IN THE SERVER
call :echo_header "Starting DB update process"
for /d %%a in (%sqlDBs%) do (
    if not [!prePatchScripts!]==[] call :run_script Pre-patching %%a !prePatchScripts!
    if not errorlevel 1 call :run_script Updating %%a !updateScript!
    if not errorlevel 1 if not [!postPatchScripts!]==[] call :run_script Post-patching %%a !postPatchScripts!
    if errorlevel 1 goto :eof
    echo.   
) 

:: ------------------------------------------------------------------------------------------------
:: END THE PROCESS SUCCESSFULLY
call :echo_header "SUCCESS: Update to %targetVersion% was successful!"
goto :eof

:: ------------------------------------------------------------------------------------------------
:: FUNCTION TO EXECUTE ONE SCRIPT ON ONE SPECIFIC DB
:: %1 the action to be performed on the DB (Updating, Pre-patching or Post-patching)
:: %2 the name of the database to execute the script on
:: %3 the name of the script(s) to be executed
:run_script
for /d %%b in (%~3) do (
    echo %1 database %2 with script %%b
    sqlcmd -b -S !serverName! -U !sqlUser! -P !sqlPwd! -d %2 -i !scriptsDir!%%b -o %logFile%
    if errorlevel 1 (
        echo Script failed on DB %2. 
        echo.
        call :restore 
        exit /b 1
    )
    echo Script executed successfully.
) 
exit /b 0

:: ------------------------------------------------------------------------------------------------
:: FUNCTION TO DISPLAY UPDATE STEP MESSAGES
:: %1 the text to be displayed as a header
:echo_header
echo ##########################################################################################
echo %~1 
echo ##########################################################################################
echo.
goto :eof

:: ------------------------------------------------------------------------------------------------
:: PERFORM DB RESTORE PROCESS
:restore
call :echo_header "Starting DB restore process"
:: Restore DB backups
for /d %%a in (%sqlDBs%) do (
    echo Restoring database: %%a from %backupDir%%%a.bak
    sqlcmd -b -S !serverName! -U !sqlUser! -P !sqlPwd! -Q "alter database [%%a] set single_user with rollback immediate"
    sqlcmd -b -S !serverName! -U !sqlUser! -P !sqlPwd! -Q "restore database [%%a] from Disk='!backupDir!%%a.bak' with replace"
    echo.
) 
call :echo_header "ERROR: Update to %targetVersion% failed. See log for details."
11 голосов | спросил carlossierra 20 AM00000020000003831 2016, 02:22:38

1 ответ


4

Стиль функции

  • Отметьте команды функции, чтобы читатель мог легко распознать, какая команда принадлежит этой функции.

  • Добавить локализацию переменных среды. Это можно сделать, выпустив команду SETLOCAL в начале функции и ENDLOCAL в конце. В противном случае все переменные внутри функции будут глобальными и, следовательно, видимыми и модифицируемыми другими скриптами. Хотя это иногда бывает удобно - это источник неприятных ошибок.

  • Назовите позиционные параметры в начале функции. Во-первых, это сделает ваш код намного понятнее. Во-вторых, когда вам нужно добавить параметры или переупорядочить их, вам не нужно будет изменять весь код, а только команды набора в начале функции.

Пример:

:echo_header
    ::
    :: Function used to display section titles inside the batch process. 
    ::
    :: %1 the text to be displayed as a header
    ::
    :: @Return errorlevel 0 always. 
    ::
    setlocal
    set header=%~1

    echo.
    echo /////////////////////////////////////////////////////////////
    echo %header%
    echo /////////////////////////////////////////////////////////////
    echo.

    endlocal
    exit /b 0

Вы должны использовать функцию, когда это возможно. Код внутри цикла может быть реорганизован как функция, так как он выполняет определенную задачу - восстановить базу данных из файла резервной копии. Во-первых, это позволит вам легко тестировать и отлаживать код. Во-вторых, намного проще повторно использовать этот код позже.

for /f "delims=" %%a in ('dir %backupsDir% /b') do (
    call :restore_db [%%a] [%backupsDir%] [%serverName%] [%sqlUser%] [%sqlPwd%]
)    
...    
:restore_db
   setlocal
   set file=%1
   set backupsDir=%2
   set serverName=%3
   set sqlUser=%4

   :: Use above variables to restore the db 
   ...
   endlocal
   exit /b 0
ответил napuzba 28 PM00000060000001731 2016, 18:45:17

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132