mts问题,《delphi5.x ado/mts/com+ 高级程序设计编》问题(300分)

  • 主题发起人 主题发起人 ls2000
  • 开始时间 开始时间
L

ls2000

Unregistered / Unconfirmed
GUEST, unregistred user!
1、事物管理
假设有下列三个mts组件,mtscord,mtswork,mtsemployee
在mtscord中有一方法如下
procedure Tmtscord.updatedat(var vdat1,vdat2:olevariant);
var
mtswork:Imtswork;
mtsemployee:Imtsemployee;
begin
try
olecheck(objectcontext.createinstance(class_mtswork,IID_imtswork,mtswork));
mtswork.updatedat1(vdat1);//更新数据
olecheck(objectcontext.createinstance(class_mtsemployee,IID_imtsemployee,mtsemployee));
mtsemployee.updatedat1(vdat2);//更新数据
setcomplete;
except
setabort;
end;
end;
mts四种事务模式,a 需要事务 b 需要新事务
c 支持事务 建议使用:支持事务,
那下面的情形
mtscord事务 mtswork事务 mtsemployee事务 vdat1、vdat2更新
A a或者b c c 应该受同一事务保护,是吗?
B c c c 会受同一事务保护吗?
C c b c mtswork的事务会传递给mtsemployee吗?
如果B、C没有受到事务保护,该怎么编代码解决呢?需要Itransactioncontextex吗?

2、是否一个组件所有的方法都受事务保护,如mtswork为需要事务
客户端
try
olecheck(objectcontext.createinstance(class_mtswork,IID_imtswork,mtswork));

mtswork.updatedat1(vdat1);//更新数据
(mtswork as Iappserver).as_applyupdates('dspwork',vdat1,0,iErrorcount,Ownerdata);
setcomplete;
except
setabort;
end;
这样AS_applyupdates是否也受与updatedat1同一事务保护?
3、midas在mts中
通过修改comobj,provider部分代码,利用dcomconnection与clientdataset连接
mts,dcomconnection会自动建立mts对象
设四个mts对象mtsquery(查询,支持事务) mtsbook(支持事务)
mtspublisher(支持事务) mtsupdate(需要事务)
mtsbook、mtspublisher分别由adoconnetion、adodataset、datasetprovider组成
mtsquery利用两个dcomconnection与clientdataset连接mtsbook与mtspublisher

mtsquery其中一方法
procedure Tmtsquery.GetBookPublisher(var vdat1,vdat2:olevariant);
begin
try
try
FdataModu.cdsBook.active:=True;
vDat1:=FdataModu.cdsBook.data;
FdataModu.cdspublisher.active:=True;
vDat2:=FdataModu.cdspublisher.data;
setcomplete;
except
setabort;
end;
finally
FdataModu.cdsBook.active:=False;
FdataModu.cdspublisher.active:=False;
end;
end;
上面的代码会受到事务保护吗?(查询数据,没有事务开销更好,是吧?)

mtsupdate利用两个dcomconnetion分别连接mtsbook、mtspublisher,其中一方法如下
procedure TmtsUpdate.updateDates(vdat1,vdat2:olevariant;imaxError:integer;
var iErrorcount:integer);
var
ownerdata:olevariant;
begin
try
(Fdatamodu.dcombooks.appserver as Iappserver).as_applyupdates('dspBooks',
vdat1,iMaxError,iErrorcount,ownerdata);
(Fdatamodu.dcompublisher.appserver as Iappserver).as_applyupdates('dsppublisher',
vdat1,iMaxError,iErrorcount,ownerdata);
setcomplete;
except
setabort;
end;
end;
这样对dspbooks与dsppublisher的更新应该会受到同一事务的保护?要是mtsupdate为支持事务模式,
客户端怎么把事务context传递给dcomconnetion呢?

4、少量多次存取问题
按书中原程序,mts模块的adodataset为
select Top 5 * from employee where emp_id>:id order by Emp_id
客户端的clientdataset的packetrecords为5
客户程序第一次建立连接时,总是取得重复的数据;并且按“more”取得下一笔数据时,显示
不正常,我在“more”中存取下一笔数据时,加上clientdataset1.refresh这样只有第一次连
接取得10条数据(5条重复的),按datasetnavigator的refresh后,显示正常(5条数据),
按”more“也正常。不知是什么原因?另外若修改了其中的数据,取下一笔数据回出现错误,
提示先更新数据applyupdate?程序中的adoquery好象有些问题,用adodataset就好了。

5、改造自己的delphi
按书中修改了好几处地方,(comobj.pas adodb.pas provider.pas 也可修改consts.pas中
的提示信息),可以把上述代码拷贝到当前的工程目录下这样连接编译时会首先使用修改过的
unit;或者把上面的pas文件和dcu文件拷贝到/bin/vcl下面。我提出第三种建议,把修改过
的单元pas与dcu拷贝到一个目录d:/vclcust(随意),然后在delphi ide中”tools“-》环境
设置-》lib path加入上面的目录路径,并提到第一位,然后在browser path中同样设置,这
样每次编译时,首先找到的是自己修改过的unit。若不要这些修改的时候,删除目录中的文件
或者改名(注意不要与/bin/vcl或其他的unit同名),delphi又还原本来面目。
 
怎么没人回答,大家尽可能的回答其中的问题吧!!!
我可以继续加分吗!
 
太长了,待我Save As 后好好研究一下。。。
 
以下是我的个人观点,一起探讨:
1.
A 是的,受到事务保护
B 也受到事务保护,但是该事务要在客户端启动
C mtswork的事务会传递给mtsemployee,但是这个地方可能会发生死锁?
2.查询受事务保护?好象没有听说过,我认为:在事务的查询中对于事务的影响不大,
但是事务启动是要消耗资源的啊
5.可以试一下,
 
1:对于"1、事物管理",我的理解是
A:情形中,mtswork和mtsemployee都会受事务保护
B:情形中,mtswork和mtsemployee都不会受事务保护
C:情形中,mtsemployee将会受mtswork事务保护
*可以用 ObjectContext.IsInTransaction 属性来判断MTS组件是否在事务中
2:我认为是的

3:
A:我想这样写更好;查询数据没有必要考虑事务问题吧?
procedure Tmtsquery.GetBookPublisher(var vdat1, vdat2: olevariant);
begin
try
try
FdataModu.cdsBook.active := True;
vDat1 := FdataModu.cdsBook.data;
FdataModu.cdspublisher.active := True;
vDat2 := FdataModu.cdspublisher.data;
//
except
setabort;
end;
finally
FdataModu.cdsBook.active := False;
FdataModu.cdspublisher.active := False;
setcomplete; //
end;
end;
B:只要客户端建立了有事务的MTS组件,当调用它的方法时,事务就已经产生了,但是:
1:令我困惑的是我做的事务更新组件必须用以下方法才能在数据更新失败失回滚。
2:另外如果该更新组件使用TSocketConnection来连接后面的组件,事务就不会产生。
procedure TfoUpdateObject.ModifyTreeNode(var TreeData: OleVariant;
var ErrorCount: Integer);
begin
if not DCOMConUser.Connected then DCOMConUser.Connected := True;
try
try
DCOMConUser.AppServer.ModifyTreeNode(TreeData, 0,ErrorCount);
if ErrorCount <> 0 then raise Exception.Create('保存出错');//必须要有这句
SetComplete;
except
SetAbort;
raise;
end;
finally
DCOMConUser.Connected := False;
end;




 
没有看上面的代码,我只说一下我对事务的一些看法.所有的事务都有一个根事务,就是上面的
a 需要事务,b 需要新事务,c 支持事务,d.不支援交易,每一个事务开始,我们都得需要a或b,
而在中间的事务,我们就用C,如果我们只用C,那么我们的数据并没有在事务保护之内.
你再把第6章 MTS/COM+的核心技术-交易管理看一下,看看里面关于事务交易的解释,我想应该
有更深一些的体会.
 
a////程序

1、pmtsdemo.dpr (pmsdemo.dll) 需要事务
数据模块mtsdemos有一个cnado:Tadoconnetion; ador:Tadodataset;
dspstud:Tdatasetprovider;
加入用户函数、过程:
function Tmtsdemos.Get_GetInfo(const st:string):olevariant;
begin //查询数据
try
cnado.connected:=true;
ador.commandtext:=st;
ador.open;
result:=dspstud.data;
ador.close;
setcomplete;
except
setabort;
end;
cnado.close;
end;

procedure tmtsdemos.applyrec(var vdata:olevariant;out succ:integer);
begin //更新数据
try
cnado.open;
dspstud.applypdates(vdata,0,succ);
setcomplete;
except
setabort;
end;
cnado.close;
end;

2、客户端pclient.exe uses pmtsdemo_tlb.pas
加入cds:Tclintdataset;并声明ms:Imtsdemos;
窗体建立时 ms:=coMtsdemos.create;
destroy时 ms:=nil;
procedure Tform1.get_infoclick(sender:tobject);
var vdata:olevariant;
begin
vdata:=ms.get_getInfo(editsql.text);
cds.data:=vdata;
cds.open;
end;

procedure Tform1.pdateR(sender:Tobject);
var
vdata:olevariant;
succ:integer;
begin
vdata:=cds.delta;
ms.updateRec(vdata,succ);
end;

b///安装到mtsdemo package中,打开组件服务发现mtsdemo包中只有一个组件
pmtsdemo.mtsdemos

c///运行客户端pclient.exe,删除、查询、更新正常。

d///观察事物运行状态
组件服务--计算机--我的电脑--com+应用服务--mtsdemo--组件--右击--
查看--属性查看:
有:prog标志:pmtsdemo.mtsdemos 事物:必需,
安全:是 同步:必须
clsid:{22ba335f-5ab3-41c1-84dc-22b02f7c66b9}
运行客户端没有见事务状态?
如果按“状态查看” 有 :prog标志,已激活, 池化, 调用中, 调用时间
运行客户端pclient开始建立mtsdemos时,已激活为1,其他为0
执行客户端“取数据”,调用时间为180,其他为0,等一会儿,全部是0;
执行客户端“更新”,调用时间为60,其他为0,等一会儿全部为0。
在外部到底怎么查看事务状态???
(程序中可用objectcontext.isintransaction)。

e///调试
mtsdemo属性 应用程序id: {334f3d3-4fe4-49ce-bfc1-f788c7912b99}
调试路径:d:/delphi5/bin/borbg50.exe dllhost.exe /processid:{334f3d3....}
delphi5 ide中设置也是/processid:{334f3d3...}没有错误,
然后在umtsdata.pas中的
function Tmtsdemos.Get_GetInfo(const st:string):olevariant;
begin //查询数据
try
cnado.connected:=true; //F5设置断点,
.....
F9运行,启动客户端pclient.exe;
在windows任务管理器中发现两个dllhost.exe进程与borbg50.exe
pclient.exe,但是pclient.exe窗体没有出现,无法调试?在ide中
run--reset停止调试,停止不了,再按一个reset出现警告
Assertion failure:"(!"nrecognized interface passed to releasedbkintf!")"
in ../win32src/dbkcom.cpp at line594点击继续,出现
access violotion at address of 02134cd8,write of address 04269962
警告,按ok,再reset出现access violotion at address of 00000000,read of address 0000000
按ok,再reset一直出现access violotion at address of 00000000,read of address 0000000
也就是退不出调试状态,客户端窗体一直没有出现。只有关闭delphi5,这时
客户端出现rpc调用失败,窗体也出现了,不知为什么???
你们真的可以调试吗???(我在安装delphi5第一次启动时的系统调试我没有选择borbg50.exe)。
 
多人接受答案了。
 
to ls2000:
看了你的代码,很受启发,有个2个问题还请赐教:
1.对于mts中,如何传递blob字段内容,找不到头绪?
原来在两层中是直接
Tblobfield(datamodule1.app_data_query.fieldbyname('blob_data')).LoadFromFile('c:/123.doc');
可以直接把文件存到blob字段中,在MTS三层中都是olevariant类型传递,该怎么办?
有人说用clientdataset也可实现上面功能,可这样就不是没有实现真正意义上的三层,即客户端
不对数据库进行操作.我想是在客户端读取文件内容,在传给中间层,由中间层控制更新等事务操作,
不知道这种做法,好不好?


 
midas与com+结合起来使用,客户端确实使用clientdataset它能从数据包里把blob字段
分离出来,注意在ado中使用tadoblobfield字段不是tblobfield
 
后退
顶部