IMHO.WS

IMHO.WS (http://www.imho.ws/index.php)
-   Программирование (http://www.imho.ws/forumdisplay.php?f=40)
-   -   DELPHI Нужна помощь! Обновление БД. (http://www.imho.ws/showthread.php?t=94936)

Galush 28.10.2005 14:59

DELPHI Нужна помощь! Обновление БД.
 
Столкнулся с проблемой при разработке многопользовательской БД.
Задача такая:
С одной таблицей работают два пользователя в одно время.
Первый пользователь изменяет данные в таблице и сохраняет их.
В то время Второй пользователь работая с этой же таблицей не получает обновленные данные, т.е. работает с неизмененными данными.
Внимание вопрос:
Как заставить сервер БД обновлять данные у всех пользователей?
Для справки. БД paradox. :help:

dyr_farot 28.10.2005 17:55

IMHO никак ( это, вобще-то нерешаемая проблема ) откуда сервер может знать нужны ли пользователю эти обновленные данные? ( а еще и такой сервер как парадокс... )

_Lynx_ 29.10.2005 00:14

Только заставляя пользователей обновлять данные вручную.
А вообще почитай про эти проблемы:
* неповторяющееся чтение (non-repeatable read);
* "грязное" чтение (dirty read) - чтение данных, которые были записаны откатанной транзакцией;
* потерянное обновление (lost update);
* фантомная вставка (phantom insert).
А также уровни изоляции и блокировки.

Willow 29.10.2005 15:06

Единственный способ - это перечитывание клиентом данных.
Обычно, в таких случаях, клиент с некоторой частотой провереяет не обновлялись ли на сервере данные (к примеру считывает время последненго обновления из специальной таблицы), и если обновляллись то перечитывает их самостоятельно.

kot_ 30.10.2005 01:17

Цитата:

Сообщение от Galush
Столкнулся с проблемой при разработке многопользовательской БД.
Задача такая:
С одной таблицей работают два пользователя в одно время.
Первый пользователь изменяет данные в таблице и сохраняет их.
В то время Второй пользователь работая с этой же таблицей не получает обновленные данные, т.е. работает с неизмененными данными.
Внимание вопрос:
Как заставить сервер БД обновлять данные у всех пользователей?
Для справки. БД paradox. :help:

Используй RDM и подпиши клиента на нужные тебе события (например вставку записи) через интрефейс СОМ.

dyr_farot 31.10.2005 13:18

kot_, подписаться пародоксу... очень сомневаюсь что получится...

kot_ 31.10.2005 16:04

:) Я имел виду не парадокс - а создать трехзвенку - и работать с ней. Я ведь так понимаю - еслиб задача совем мизирная была и одноразовая - и проблем бы особых не было. Плюсы - можно спокойно забыть о недостатках файлсервера, спокойно реализовать все бизнес правила, создать нужный функционал. Минус - прийдется попарится с СОМ-серверами и внести изменения в существующую программу. Иногда конечно подобные минуса перевешивают все плюса - но тут уже по месту.

gscorp 02.11.2005 15:59

Цитата:

kot_:
Я имел виду не парадокс - а создать трехзвенку - и работать с ней
IMHO Задача мягко говоря грандиозна - превращать файлсервер в версионник... гм.... я бы не решился.
Цитата:

kot_:
Минус - прийдется попарится с СОМ-серверами
COM - Сервера под делфей пишится на раз, вопрос здесь один разруливание доступа к разделяемому ресурсу...

kot_ 02.11.2005 16:31

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

Galush 03.11.2005 10:39

Цитата:

kot_:
Можно в принципе - что бы не переделывать приложение - реализовать отдельно сервер уведомлений.
Можно как нить по подробнее.

kot_ 03.11.2005 16:32

Блин. Сервак падает раз, за разом.
Че за байда?
Что бы написать и отправить пост - четыре часа уходит
******************
Можно. Один из вариантов - создаешь сервер уведомлений на основе хотябы тогоже билдеровского РДМ-модуля. Делается это достаточно просто - создаешь новый проект - в него добаваляешь 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);
//Если есть новые сообчения - генерим событие.

}

Надеюсь как обработать событие на клиенте - писать не надо? :)
Ну вот в принципе и все. Просто у меня сервер решает более сложные задачи, которые может быть в твоем случае и на.х не нужны - и работа с базой у меня тоже идет через него. По этому я не расписывал функции логирования на сервер - главное - ты должен создать объект пользователя, приципить к нему уникальный ид и привязать ссылки на дм и рдм. И соответственно при дисконнекте - это все освободить. Да - еще это предполагает что ты пользуешься моделью взаимодействия фри - при аппартменте возможно будет гораздо проще - просто на каждого юзера будет стартовать сое приложение.


Часовой пояс GMT +4, время: 07:17.

Powered by vBulletin® Version 3.8.5
Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.