Опубликован: 07.05.2010 | Уровень: специалист | Доступ: свободно
Лекция 27:

Программное администрирование баз данных InterBase

< Лекция 26 || Лекция 27: 12345 || Лекция 28 >

Соображаем дальше. Копирование у нас будет начинаться либо по нажатию кнопки, либо по срабатыванию таймера, в зависимости от того, какая радиокнопка выделена. Значит, чтобы дважды не писать один и тот же код, создадим процедуру резервного копирования, которую будем вызывать из двух мест. Поскольку процедура будет напрямую работать с компонентом IBBS, вначале объявим ее в разделе private, после функции GetName:

private
    { Private declarations }
    function GetName():String;
    procedure BackupCopy;

Установите курсор на процедуру и нажмите <Ctrl+Shift+C>, чтобы сгенерировать тело процедуры. Ее код:

{Процедура реализации резервного копирования}
procedure TfMain.BackupCopy;
var s : String; //для получения префикса файла
begin
  //получим префикс:
  s:= GetName();
  //очистим Memo1, если там что то есть:
  Memo1.Clear;
  //задаем параметры компонента IBBackupService:
  IBBS.ServerName := 'MyServ';
  IBBS.LoginPrompt:= False;
  IBBS.Params.Add('user_name=sysdba');
  IBBS.Params.Add('password=masterkey');
  IBBS.Active := True;
  //начинаем копирование
  try
    IBBS.Verbose:= True;
    IBBS.DatabaseName:= 'c:\DataBases\first.gdb';
    IBBS.BackupFile.Clear;
    IBBS.BackupFile.Add('c:\DataBases\Backup\' + 
s + 'first.gbk');
    IBBS.ServiceStart;
    //пока не дошли до конца, записываем параллельно лог в Memo1:
    while not IBBS.Eof do
      Memo1.Lines.Add(IBBS.GetNextLine);
  finally
    IBBS.Active:= False;
  end;
  //сохраним лог в файл:
  Memo1.Lines.SaveToFile('c:\DataBases\Backup\' +  
s + 'first.log');
end;

Здесь мы вначале получили в переменную префикс имени файла. Зачем это нужно? Нам требуется:

  1. Сделать резервную копию.
  2. Сохранить лог копирования в файл.

Эти действия будут производиться в разное время, поэтому чтобы префикс копии совпадал с префиксом лог-файла, мы и сохраняем его в переменную s:

//получим префикс:
  s:= GetName();

Далее мы очищаем Memo1, если вдруг там уже был текст. После чего приступаем к настройкам параметров компонента IBBS:

IBBS.ServerName := 'MyServ';
  IBBS.LoginPrompt:= False;
  IBBS.Params.Add('user_name=sysdba');
  IBBS.Params.Add('password=masterkey');
  IBBS.Active := True;

Тут все достаточно прозрачно. Поскольку копирование будет производиться на серверном ПК, то будет использован локальный адрес, следовательно, свойство ServerName мы можем назвать, как угодно. Если бы сервер был сетевым, пришлось бы писать сетевое имя этого ПК, или его IP -адрес. При этом следует обратить внимание на свойство Protocol. Это свойство позволяет выбрать протокол соединения. Поскольку программа будет загружаться там же, где установлен InterBase и где хранится база данных, оставляет значение по умолчанию - Local. Если программа будет работать с удаленным сервером, то здесь нужно будет выбрать один из сетевых протоколов, обычно выбирают TCP.

Далее с помощью LoginPrompt мы заявляем, что не нужно запрашивать имя пользователя и пароль (кто же введет эти данные в час ночи, когда запустится авто-копирование?). Затем мы вводим в свойство Params имя пользователя SYSDBA и его пароль. Если вы изменили пароль (а это обязательно нужно сделать в реальной системе), вместо " masterkey " укажите свой пароль. В конце мы делаем IBBS активным.

Само копирование мы помещаем в блок try…finally…end, поскольку копирование может быть и неудачным, если БД разрушена:

try
    IBBS.Verbose:= True;
    IBBS.DatabaseName:= 'c:\DataBases\first.gdb';
    IBBS.BackupFile.Clear;
    IBBS.BackupFile.Add('c:\DataBases\Backup\' + s + 'first.gbk');
    IBBS.ServiceStart;
    //пока не дошли до конца, записываем параллельно лог в Memo1:
    while not IBBS.Eof do
      Memo1.Lines.Add(IBBS.GetNextLine);
  finally
    IBBS.Active:= False;
  end;

Здесь свойство Verbose (многословность) определяет - будет ли выводиться лог резервного копирования. При значении True лог ведется, иначе - нет. Нам нужно, чтобы лог создавался.

В свойство DatabaseName помещаем адрес и имя нашей рабочей базы данных.

Свойство BackupFile должно содержать имя файла (или файлов) резервной копии. У нас база данных состоит из одного файла, и резервная копия также будет состоять из одного файла, поэтому прежде, чем мы поместим туда имя очередной резервной копии, это свойство нужно очистить. Затем формируем имя файла из адреса, префикса и самого имени " first.gbk". А затем стартуем копирование методом ServiceStart. Заметим, что установка True в свойстве Active компонента не начинает резервное копирование, а только делает компонент активным.

Параллельно копированию в компонент Memo1 помещаем отчет о текущем действии, от начала копирования до конца. Метод GetNextLine компонента IBBackupService возвращает очередную строку лог-отчета. Когда копирование окончено, делаем компонент IBBS неактивным.

И в самом конце процедуры записываем полученный в Memo1 лог в файл с таким же именем, как резервная копия, но расширением *.log:

//сохраним лог в файл:
  Memo1.Lines.SaveToFile('c:\DataBases\Backup\' +  
s + 'first.log');

Теперь для ручного копирования нам осталось сгенерировать процедуру нажатия на кнопку "Начать копирование", откуда вызовем процедуру BackupCopy:

{Нажали на кнопку "Начать копирование"}
procedure TfMain.bStartBackupClick(Sender: TObject);
begin
  BackupCopy;
end;

Попробуйте выполнить ручное копирование. Напомню, что сервер InterBase должен быть запущен, а папка " C:\DataBases\Backup " должна физически существовать на диске. Как только вы нажмете на кнопку, копирование начнется. Закончится оно примерно такой строкой:

gbak: closing file, committing and finishing. 38912 bytes written.

Зайдите в папку Backup - там должна появиться пара файлов с одинаковым именем и расширениями *.gbk и *.log. Это и есть наши резервная копия и лог-файл.

Займемся автоматическим копированием. Выделите таймер и сгенерируйте для него событие onTimer, которое будет срабатывать каждую минуту ( Interval =60000):

{Сработал таймер}
procedure TfMain.Timer1Timer(Sender: TObject);
var
  ho, mi, se, ms : Word; //для времени
begin
  //если включено ручное копирование, просто выходим:
  if RB1.Checked then Exit;
  //иначе декодируем время
  DecodeTime(Time, ho, mi, se, ms); //декодируем время
  //если нужный час и нужная минута, начинаем копирование:
  if (ho = SE1.Value) and (mi = SE2.Value) then BackupCopy;
end;

Вначале мы проверяем, не включено ли ручное копирование. Если включено, то сразу выходим, ничего не делая. Затем мы снова декодируем время, чтобы посмотреть - совпадают ли данные в компонентах SpinEdit с текущими часом и минутой. И если совпадают, вызываем процедуру BackupCopy.

Заметим, что таймер может сработать не сразу, как системные часы покажут нужное время. Ведь в таймере учитываются и секунды. Значит, если копирование у нас должно начаться в 01:00, а когда программа была запущена, ваше системное время показывало, скажем, 25 секунд, то и таймер сработает в 01:00:25. Что, в принципе, не столь важно.

Сохраните проект, скомпилируйте и запустите. Попробуйте установить время авто-копирования на минуту-другую больше, чем показывают ваши системные часы (должна быть выделена радиокнопка "Автоматическое копирование"). Дождитесь, когда системное время сравняется с указанным. Возможно, придется подождать еще несколько секунд, после чего резервное копирование начнется автоматически. Опять появится пара файлов в папке Backup. Таким образом, достаточно выделить радиокнопку RB2 (у нас она выделена по умолчанию), и не выключать на сервере программу, чтобы обеспечить регулярное резервное копирование базы данных. Разумеется, серверный ПК с InterBase, вашей базой данных и администраторской программой должен быть включен в назначенное время (серверные компьютеры обычно работают в режиме 24/7, то есть 24 часа в сутки, 7 дней в неделю).

Напоследок заметим, что компонент IBBackupService имеет сложное раскрывающееся свойство Options, которое имеет следующие переключатели:

Таблица 27.1 . Переключатели свойства Options компонента IBBackupService
Переключатель Описание
IgnoreChecksums Игнорировать ошибки контрольных сумм. Применяется обычно при попытке восстановить поврежденную БД.
IgnoreLimbo Игнорировать ошибки двухфазного подтверждения limbo -транзакций. Также применяется при восстановлении поврежденной БД.
MetadataOnly При включенном переключателе в резервную копию попадут только метаданные. Можно использовать, если вы хотите получить пустую БД с таблицами, индексами, генераторами, триггерами и проч., но без записей.
NoGarbageCollection Не делать сборку мусора во время резервного копирования.
OldMetadataDesc Делать резервную копию в старом стиле. Как правило, не применяется.
NonTransportable Делать резервную копию, непереносимую на другие версии InterBase (а также Firebird и Yaffil ).
ConvertExtTables Преобразует внешние файлы во внутренние таблицы. Также может применяться при восстановлении поврежденной БД.

Как видно из таблицы, резервное копирование можно делать с некоторыми параметрами. Мы не использовали этих параметров, то есть, делали копию с параметрами "по умолчанию". В результате получили обычную резервную копию, для чего и нужна наша программа. Если же доведется ремонтировать базу данных, то делать это нужно утилитами gfix и gback, которые предоставляют гораздо больше возможностей, чем указанные переключатели.

< Лекция 26 || Лекция 27: 12345 || Лекция 28 >
Евгений Медведев
Евгений Медведев

В лекции №2 вставляю модуль данных. При попытке заменить name на  fDM выдает ошибку: "The project already contains a form or module named fDM!". Что делать? 

Анна Зеленина
Анна Зеленина

При вводе типов успешно сохраняется только 1я строчка. При попытке ввести второй тип вылезает сообщение об ошибке "project mymenu.exe raised exception class EOleException with message 'Microsoft Драйвер ODBC Paradox В операции должен использоваться обновляемый запрос'.