Delphi-Help

Главная Статьи Paradox Использование баз данных Paradox в локальной сети

Использование баз данных Paradox в локальной сети

Оцените материал
(0 голосов)


Использование баз данных Paradox в локальной сети

Хотелось бы поделиться опытом использования баз данных Paradox в локальной сети. По большому счету, принципы распределенного и локального доступа к таблицам Paradox ничем не отличаются. Исключения составляют некоторые правила и рекомендации, которые изложены ниже...

В последнее время в сторону BDE раздается много замечаний и нареканий по поводу ограниченности и ненадежности при организации сетевого доступа к файлам БД.

Существует множество решений и хитростей, призваных облегчить жизнь разработчику, работающему с BDE. Как показывает опыт, такие эксперименты чаще всего приводят к частичной и полной потере данных в файловых таблицах... Отсюда правило первое : если вы хотите использовать Paradox в сети, установите BDE в полном объеме на каждой клиентской машине, включая ту, где находятся файлы базы данных. Обязательны следующие установки в конфигурации на каждой машине :

Это предотвратит Sharing Violation :

BDE->Configuration->System->Init : LOCAL SHARE = TRUE

BDE->{Самое важное}

Это предотвратит неразбериху в местоположении данных.

BDE не работает с базами данных напрямую, как например \\head\C\Database.

Диск с данными необходимо подключить как сетевой. Еще лучше, если буквы сетевого диска будут одинаковыми на всех машинах...

BDE->Configuration->Drivers->Native->Paradox : NETDIR = F:\Databse,

BDE->где F = \\head\c\

Возникает резонный вопрос : а что если баз данных несколько?

Тогда в качестве NETDIR необходимо указать корневой каталог, в нашем случае F.

Если вы работаете с файловыми базами данных, то вам необходимо воспринимать BDE как некоторый сервис, как скажем, interbase. Сравнение конечно не из лучших, однако нормально работающий BDE - залог сохранности и надежности ваших данных.

К вопросу о Refresh.

Если вы работаете локально, то никаких проблем с обновлением набора данных у вас не возникает. При изменении данных, вы сразу видите результат на экране. В сети ситуация несколько иная : пользователи на других компьютерах не видят тех изменений, которые происходят без их участия. Конечно, ничто не мешает нам через определенные интервалы времени обновлять элементы управления с помощью Refresh, однако не очень приятно наблюдать за тем, как ваша программа превращается в новогоднюю елку, постоянно мерцая элементами управления. Проблема решается с помощью BDE Callback Functions :

// Объявления...
TForm1 = class(TForm)
  // ...
public
  function TableChangeCallBack(CBInfo: Pointer): CBRType;
  procedure UpdateTableData(var Msg: TMessage); message WM_UPDATETABLE;
  procedure TablesAfterOpen(DataSet: TDataSet);
end;
 
// Реализация...
 
function TForm1.TableChangeCallBack(CBInfo: Pointer): CBRType;
begin
  PostMessage(Handle, WM_UPDATETABLE, 0, 0);
end;
 
procedure TForm1.UpdateTableData(var Msg: TMessage);
var
  Index: Integer;
begin
  for Index := 0 to DBDataModule.ComponentCount - 1 do
    // DBDataModule - это Data module, в котором находятся все
    // TTable нашего   проекта...
    if DBDataModule.Components[Index] is TTable then
      if TTable(DBDataModule.Components[Index]).State = dsBrowse then
        TTable(DBDataModule.Components[Index]).Refresh;
end;
 
procedure TForm1.TablesAfterOpen(DataSet: TDataSet);
begin
  TBDECallback.Create(Self, TTable(DataSet).Handle, cbTableChanged, nil, 0,
    TableChangeCallBack, True);
end;
// На событие OnCreate в Data Module подключаем наши функции к TTable...
 
procedure TDBDataModule.DBDataModuleCreate(Sender: TObject);
var
  Index: Integer;
begin
  for Index := 0 to ComponentCount - 1 do
    if Components[Index] is TTable then
      TTable(Components[Index]).AfterOpen := Form1.TablesAfterOpen;
end;

Но и это еще не все...Теперь нам нужен TTimer..

.procedure TForm1.FrashmanTimer(Sender: TObject);
var
  Index: Integer;
begin
  try
    for Index := 0 to DBDataModule.ComponentCount - 1 do
      if DBDataModule.Components[Index] is TTable then
        if (TTable(DBDataModule.Components[Index]).Active)
          and
          (TTable(DBDataModule.Components[Index]).State = dsBrowse) then
          DBIForceReRead(TTable(DBDataModule.Components[Index]).Handle);
  except
  end;
end;

Сохранность данных в сети.

Для того чтобы быть уверенным в сохранности данных, необходимо на событие AfterPost Компонета TTable назначить следующее :

dbiSaveChanges(TTable(DataSet).Handle);

Блокировки. Существует два подхода к разделенному изменению данных: оптимистический и писсимистический.В первом случае речь идет о клиент - сервере и транзакциях.Иначе говоря, сколько угодно пользователей могут одновременно изменять одни и те же данные.В нашем случае такой возможности просто не существует. Необходимо самим предусмотреть ситуацию, когда пользователи, например, попытаются одновременно редактировать одну и ту же запись. Ничего страшного, кроме сообщения "record locked by another user", не произойдет. Однако желательно самим обработать данную ситуацию. Вот пример функции, которая проверяет, заблокирована запись или нет:}

function IsRecordLocked(Table: TTable): Boolean;
var
  Locked: BOOL;
  hCur: hDBICur;
  rslt: DBIResult;
begin
  Table.UpdateCursorPos;
  Check(DbiIsRecordLocked(Table.Handle, Locked));
  Result := Locked;
  if (Result = False) then
  begin
    Check(DbiCloneCursor(Table.Handle, False, False, hCur));
    try
      rslt := DbiGetRecord(hCur, dbiWRITELOCK, nil, nil);
      if rslt <> DBIERR_NONE then
      begin
        if HiByte(rslt) = ERRCAT_LOCKCONFLICT then
          Result := True
        else
          Check(rslt);
      end
      else
        Check(DbiRelRecordLock(hCur, False));
    finally
      Check(DbiCloseCursor(hCur));
    end;
  end;
end;
Прочитано 6114 раз

Авторизация



Счетчики