Хотелось бы поделиться опытом использования баз данных 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)
// ...publicfunction 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);
varIndex: Integer;
beginforIndex := 0 to DBDataModule.ComponentCount - 1 do// DBDataModule - это Data module, в котором находятся все// TTable нашего проекта...if DBDataModule.Components[Index] is TTable thenif 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);
varIndex: Integer;
beginforIndex := 0 to ComponentCount - 1 doif Components[Index] is TTable then
TTable(Components[Index]).AfterOpen := Form1.TablesAfterOpen;
end;
Но и это еще не все...Теперь нам нужен TTimer..
.procedure TForm1.FrashmanTimer(Sender: TObject);
varIndex: Integer;
begintryforIndex := 0 to DBDataModule.ComponentCount - 1 doif DBDataModule.Components[Index] is TTable thenif (TTable(DBDataModule.Components[Index]).Active)
and
(TTable(DBDataModule.Components[Index]).State = dsBrowse) then
DBIForceReRead(TTable(DBDataModule.Components[Index]).Handle);
exceptend;
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) thenbegin
Check(DbiCloneCursor(Table.Handle, False, False, hCur));
try
rslt := DbiGetRecord(hCur, dbiWRITELOCK, nil, nil);
if rslt <> DBIERR_NONE thenbeginif HiByte(rslt) = ERRCAT_LOCKCONFLICT then
Result := True
else
Check(rslt);
endelse
Check(DbiRelRecordLock(hCur, False));
finally
Check(DbiCloseCursor(hCur));
end;
end;
end;
Использование баз данных Paradox в локальной сети: правила и рекомендации для обеспечения безопасности и сохранности данных.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.