| imho.ws |
![]() |
|
|
|
# 1 |
|
Banned
Регистрация: 08.08.2005
Адрес: ЗАВОД на УКЕ
Сообщения: 52
![]() |
DELPHI Нужна помощь! Обновление БД.
Столкнулся с проблемой при разработке многопользовательской БД.
Задача такая: С одной таблицей работают два пользователя в одно время. Первый пользователь изменяет данные в таблице и сохраняет их. В то время Второй пользователь работая с этой же таблицей не получает обновленные данные, т.е. работает с неизмененными данными. Внимание вопрос: Как заставить сервер БД обновлять данные у всех пользователей? Для справки. БД paradox.
|
|
|
|
|
# 3 |
|
Junior Member
Регистрация: 11.10.2005
Сообщения: 63
![]() |
Только заставляя пользователей обновлять данные вручную.
А вообще почитай про эти проблемы: * неповторяющееся чтение (non-repeatable read); * "грязное" чтение (dirty read) - чтение данных, которые были записаны откатанной транзакцией; * потерянное обновление (lost update); * фантомная вставка (phantom insert). А также уровни изоляции и блокировки. |
|
|
|
|
# 4 |
|
Junior Member
Регистрация: 23.12.2003
Адрес: Киев
Сообщения: 118
![]() ![]() ![]() ![]() |
Единственный способ - это перечитывание клиентом данных.
Обычно, в таких случаях, клиент с некоторой частотой провереяет не обновлялись ли на сервере данные (к примеру считывает время последненго обновления из специальной таблицы), и если обновляллись то перечитывает их самостоятельно. |
|
|
|
|
# 5 | |
|
Junior Member
Регистрация: 19.11.2004
Адрес: Dnepropetrovsk
Пол: Male
Сообщения: 67
![]() |
Цитата:
__________________
|
|
|
|
|
|
# 7 |
|
Junior Member
Регистрация: 19.11.2004
Адрес: Dnepropetrovsk
Пол: Male
Сообщения: 67
![]() |
Я имел виду не парадокс - а создать трехзвенку - и работать с ней. Я ведь так понимаю - еслиб задача совем мизирная была и одноразовая - и проблем бы особых не было. Плюсы - можно спокойно забыть о недостатках файлсервера, спокойно реализовать все бизнес правила, создать нужный функционал. Минус - прийдется попарится с СОМ-серверами и внести изменения в существующую программу. Иногда конечно подобные минуса перевешивают все плюса - но тут уже по месту.
__________________
|
|
|
|
|
# 8 | ||
|
Newbie
Регистрация: 21.10.2005
Сообщения: 24
![]() |
Цитата:
Цитата:
__________________
в память о 2:5049/70 |
||
|
|
|
|
# 9 |
|
Junior Member
Регистрация: 19.11.2004
Адрес: Dnepropetrovsk
Пол: Male
Сообщения: 67
![]() |
Для начала - необязательно для этого заморачиваться с версионностью - при вставке/изменении записи - для начала генерить событие и обработать его в приложении. Ничего особо грандиозного в данном случае нет и задачу способно решить без особо дополнительных расходов. Можно в принципе - что бы не переделывать приложение - реализовать отдельно сервер уведомлений. Это будет достаточно простое решение - правда не очень изящное. Вопрос ведь был задан - как уведомить пользователя о изменении, а не как реализовать версионность. Ком -сервер вполне эту задачу может выполнить, а если понадобится разруливание доступов - это тоже в тех же дельфях телается за день.
__________________
|
|
|
|
|
# 11 |
|
Junior Member
Регистрация: 19.11.2004
Адрес: Dnepropetrovsk
Пол: Male
Сообщения: 67
![]() |
Блин. Сервак падает раз, за разом.
Че за байда? Что бы написать и отправить пост - четыре часа уходит ****************** Можно. Один из вариантов - создаешь сервер уведомлений на основе хотябы тогоже билдеровского РДМ-модуля. Делается это достаточно просто - создаешь новый проект - в него добаваляешь RDM-модуль(не забудь поставить галочку в эвентсах) и модель выбирай о вкусу - апартмент - на каждого юзера запускается отдельное приложение например, я предпочитаю фри - но эта модель достаточно сложна. Сохраняешь и лезешь в Type Library и в интерфейсах своего класса прописываешь необходимые тебе функции. В импл-модуле определяешь их. После определяешь какие события будут ловиться на твоих клиентах. Соответственно объявляешь их. Дальше свой сервер запускаешь с параметром /regserver. В принципе с сервером все. А ну соответственно в классе формы и классе интерфейса надо определить функции - это ниже. Для клиента прийдется написать заголовочный файл интерфейса класса событий и подключить в проект. Выглядит примерно так:Код:
#if !defined (NOTCREMOUTESINK_H__)
#define NOTCREMOUTESINK_H__
#include <atlvcl.h>
#include <atlbase.h>
#include <atlcom.h>
#include <ComObj.HPP>
#include <utilcls.h>
#include "..\server\srvnotc_TLB.h"// Файл интерфейсов твоего сервера
//генерируется автоматически в проекте сервера.
typedef void __fastcall (__closure *TNewMessageEvents)( long employeeid );
typedef void __fastcall (__closure *TChangeStatusEvents)( BSTR contractid,long pointid );
//Ловим два события: Вызов фукции сервера GetNewMessage()
//получаем в нем идентификатор пользователя !которому! направлено сообщение
//Изменение статуса записи - событие генерируется при вызове функции InsertContract&UpdateContract
//Остальные сделаешь по примеру - а то листинг
//Твой класс уведомлений
class TnOTCRemouteSink :
public TEventDispatcher<TnOTCRemouteSink, &DIID_InOTCRemouteModuleEvents>
{
protected:
TNewMessageEvents FOnNewMessage;
TChangeStatusEvents FOnChangeStatus;
...
HRESULT InvokeEvent(DISPID id, TVariant* params)
{
if ((id == 1) && (FOnNewMessage!= NULL)) FOnNewMessage(params[0]);
else if ((id == 2) && (FOnChangeStatus != NULL))
FOnChangeStatus(params[0],params[1]);
...
return S_OK;
}
CComPtr<IUnknown> m_pSender;
public:
__property TNewMessageEvents OnNewMessage =
{ read = FOnNewMessage, write = FOnNewMessage };
__property TChangeStatusEvents OnChangeStatus =
{ read = FOnChangeStatus, write = FOnChangeStatus };
...
public:
TnOTCRemouteSink() :
m_pSender(NULL),
FOnNewMessage(NULL),
FOnChangeStatus(NULL)
{
}
virtual ~TnOTCRemouteSink()
{
Disconnect();
}
void Connect(IUnknown* pSender)
{
if (pSender != m_pSender)
m_pSender = pSender;
if (NULL != m_pSender)
ConnectEvents(m_pSender);
}
void Disconnect()
{
if (NULL != m_pSender)
{
DisconnectEvents(m_pSender);
m_pSender = NULL;
}
}
};
#endif
Код:
TCOMInOTCRemouteModule m_remoute;//Твой сервер уведомлений
TnOTCRemouteSink RMSick;//
...
Srvnotc_tlb::ConOTCRemouteModule::CreateRemote(WideString("you_host"),m_remoute);
RMSick.OnNewMessage = TgfmMain::OnNewMessage;
RMSick.OnChangeStatus = TgfmMain::OnChangeStatus;
...
RMSick.Connect(m_remoute);
m_remoute->GetMessageEm(&myid);
//////////////На сервере функция GetMessage определяется примерно так:
....
STDMETHODIMP TnOTCRemouteModuleImpl::GetMessageEm(long id){
fmMain->GetMessageEmp(id);
return S_OK;
}
....
///
void __fastcall TfmMain:: GetMessageEmp(long id){
int Index = GetRecordIndexById(id);
//employeeV - ето вектор структур TEmployee - которые содержат инфу о подключенных в данный момент юзерах - заполняется в функции Login.
//Соответсвенно GetRecordIndexById(id) - возвращает индекс в векторе по иду пользователя.
//employeeV[Index].dm - указатель на датамодуль,employeeV[Index].ra - указатель на интерфейс сервера
//все это опять же инициализируется при логине.
// Можно реализовать это все гораздо проще - или сложней :)
if(employeeV[Index].dm->adoGetMessage->Active)employeeV[Index].dm->adoGetMessage->Active = false;
employeeV[Index].dm->adoGetMessage->Parameters->ParamByName("@id")->Value = id;
employeeV[Index].dm->adoGetMessage->Active = true;
if(employeeV[Index].dm->adoGetMessage->RecordCount)
employeeV[Index].ra->Fire_OnNewMessage(employeeV[Index].id);
//Если есть новые сообчения - генерим событие.
}
![]() Ну вот в принципе и все. Просто у меня сервер решает более сложные задачи, которые может быть в твоем случае и на.х не нужны - и работа с базой у меня тоже идет через него. По этому я не расписывал функции логирования на сервер - главное - ты должен создать объект пользователя, приципить к нему уникальный ид и привязать ссылки на дм и рдм. И соответственно при дисконнекте - это все освободить. Да - еще это предполагает что ты пользуешься моделью взаимодействия фри - при аппартменте возможно будет гораздо проще - просто на каждого юзера будет стартовать сое приложение.
__________________
|
|
|