Использование Microsoft Transaction Server

Обратите внимание: ни компонент TTable, ни компонент TProvider не следует экспортировать из модуля данных. Причина этого заключается в том, что подобные экспортированные объекты хранят состояние данных, с которыми работает конкретное клиентское приложение, поэтому при коллективном использовании таких объектов могут возникнуть коллизии. По этой причине сведения о состоянии данных для конкретных клиентов хранятся менеджером разделяемых свойств MTS (MTS shared property manager), а в модулях данных между вызовами методов эти сведения присутствовать не должны. Поэтому вместо экспорта объектов из модуля данных мы создадим метод GetGoods, предоставляющий эти данные клиентскому приложению по его запросу. После этого можно отредактировать библиотеку типов. Добавим к ней методы GetGoods для передачи клиентскому приложению содержимого таблицы и методы AddGoods и DeleteGoods для выполнения запросов, содержащихся в компонентах TQuery (рис. 12): clip0110 Рис. 12. Библиотека типов серверного объекта Реализация созданных методов приведена ниже:

unit st1;
//Simple MTS server
//By N.Elmanova
//01.12.1998
interface
uses
 Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
 ComServ, ComObj, VCLCom, StdVcl, BdeProv, BdeMts, DataBkr, DBClient,
 MtsRdm, Mtx, st_TLB, DBTables, Provider, Db;
type
 TStockDM1 = class(TMtsDataModule, IStockDM1)
  stable: TTable;
  StProvider: TProvider;
  Database1: TDatabase;
  Query1: TQuery;
  Query2: TQuery;
  Session3: TSession;
 private
  { Private declarations }
 public
  { Public declarations }
 protected
  function GetGoods: OleVariant; safecall;
  procedure AddGoods(const Gname: WideString; Gprice: Double); safecall;
  procedure DeleteGoods(Gnumber: Integer); safecall;
 end;
var
 StockDM1: TStockDM1;
implementation
{$R *.DFM}
function TStockDM1.GetGoods: OleVariant;
begin
 Result:=StProvider.Data;
 SetComplete;
end;
procedure TStockDM1.AddGoods(const Gname: WideString; Gprice: Double);
begin
try
 Database1.Open;
 Query1.Params[0].Value:=Gname;
 Query1.Params[1].Value:=Gprice;
 Query1.Prepare;
 Query1.ExecSQL;
 Database1.Сlose;
 SetComplete;
except
 SetAbort;
 raise;
end;
end;
procedure TStockDM1.DeleteGoods(Gnumber: Integer);
begin
try
 Database1.Open;
 Stable.open;
 Stable.SetRangeStart;
 Stable.Fields[2].AsInteger:=Gnumber;
 Stable.SetRangeEnd;
 Stable.Fields[2].AsInteger:=Gnumber;
 Stable.ApplyRange;
 Stable.Delete;
 Database1.Close;
 SetComplete;
except
 SetAbort;
 raise;
end;
end;
initialization
 TComponentFactory.Create(ComServer, TStockDM1,
  Class_StockDM1, ciMultiInstance, tmApartment);
end.

Прокомментируем приведенный выше код. Напомним, что мы не экспортировали компонент TProvider или компонент TTable из модуля данных, а вместо этого создали метод GetGoods, предоставляющий клиентскому приложению данные из таблицы динамически, позволяя не хранить сведения о состоянии данных в серверном объекте. Метод GetGoods представляет собой так называемый "stateless code", а сам модуль данных в этом случае представляет собой так называемый "stateless object" (об этом было рассказано выше). Именно отсутствие статических данных, связанных с конкретным клиентом, позволит в дальнейшем сделать этот модуль данных разделяемым ресурсом.
Вызов метода SetComplete внутри метода GetGoods означает, что модуль данных более не нуждается в хранении информации о состоянии и может быть деактивирован. Если модуль данных представляет собой одну из частей распределенной транзакции (пока это не так, но чуть позже он станет одной из таких частей), этот метод означает, что данная часть транзакции может быть завершена (естественно, при условии, что все другие части этой транзакции также могут быть завершены; в противном случае произойдет откат транзакции, в том числе и данной части). Если же MTS начинает транзакцию автоматически при создании модуля данных (опция Requires a transaction), вызов метода SetComplete приведет к попытке ее завершения.
Перед компиляцией проекта рекомендуется убедиться, что компоненты TDatabase, TSession, TTable неактивны.
Далее следует выбрать из меню Delphi опцию Run/Install MTS Objects. После этого следует выбрать или ввести имя "пакета" MTS (MTS package). После этого объект окажется зарегистрированным в MTS (рис. 13):
clip0111
Рис. 13. Серверный объект StockDM1, зарегистрированный в MTS
Следует обратить внимание на то, что регистрировать серверный объект как обычный COM-сервер не следует - в роли сервера с точки зрения реестра для клиента в данном случае выступает MTS, а не созданная библиотека.
При попытках внесения неоднократных изменений в код серверного объекта и запуска сервера с помощью собственно MTS или обращающихся к нему клиентов могут возникнуть проблемы. В частности, может оказаться, что при попытке компиляции библиотеки появляется сообщение о невозможности создания выходного файла. Это может быть связано с тем, что какие-то экземпляры объекта уже созданы в адресном пространстве MTS, поэтому файл оказался заблокированным. В этом случае следует в MTS Explorer найти соответствующий "пакет" и из его контекстного меню выбрать опцию Shut down. Можно также выбрать в MTS Explorer раздел My Computer и из его контекстного меню выбрать опцию Shut down server processes, прекратив таким образом существование всех серверных объектов. Кроме того, можно уменьшить время существования серверного объекта в неактивном состоянии. Это делается с помощью выбора пункта контекстного меню Properties соответствующего пакета и установкой необходимого значения свойства Shut down after being idle for… на странице Advanced появившейся диалоговой панели.

Отправить комментарий

Содержание этого поля является приватным и не предназначено к показу.
Проверка
Антиспам проверка
Image CAPTCHA
...