为什么调用一个中间层的方法,就会在Sql Server上多开一个进程?内详,高手请进!(100分)

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

lichaogang

Unregistered / Unconfirmed
GUEST, unregistred user!
我的中间层是用的MTS,在一个套件中是有一个共享的AdoConnection组件,所有的数据集都是用这一个Connection组件。此组件只在中间层被创建时执行一次连接数据库的动作。但今天发现,每次调用一个中间层的方法,Sql Server都会相应的产生一个进程,方法执行完之后这个进程就是Sleeping的,但只到中间层关闭之后这些进程才会被释放!!这样的话对于Sql Server而言,不是很快就会达到它的连接上限???
跟踪程序得知,在每次进行查询时,ADO会先判断数据集的Connection是否是Connected的,如若不是则Connect,就是这里导致Sql Server又多开了进程!而对是数据集而言,执行过查询之后,它的Connection又关闭了(是不是MTS控制的?)。
请问高手,这种现象是否正常?该如何改进????
 
Sql Server 会产生一个进程,线程吧。
SqlServer是会产生很多线程(线程池)用来执行Sql啊,这很正常,和你的客户端连接没有关系。
 
spid不同啊!一个Spid是不是代表了一个连接?
 
很正常啊。不过在中间层中,不用显示打开连接。
ADO会先判断数据集的Connection是否是Connected的。不用这样做,取数据时会自动连接。
 
很正常,我公司的sql server 常常有成千個這樣的東西....
 
to eboy_wy:没错,我所说的也是,这是实现在Ado内的!
to kouchun:但我发现若使用sp_who查看spid超过两百个后系统反应速度明显变慢!
 
这个问题我也遇到过,本来我把ADOconnection组件定义成局部变量,认为function结束的时候系统会自己释放掉它,结果sql server上的连接数不断增加。我的问题是这样解决的,把那个ADOConnection组件每次调用完毕之后,Free掉它,sql server上的连接就会被释放了。
另外还有一个建议,把ADOConnetion组件在com+中池化。可以减少创建sql连接的次数,提高效率。
 
在COM+中池化
 
正常正常
 
这样的话,肯定是要用连接池的啊!连接池的例子已经很多了,这里就不说了。
 
找到问题,并非如我上面所说,最主要是因为共享方法有问题。
现在我将包含Connection的组件在所有组件的Create之前先生成一份并一直保存在中间层,直到整个套件被MTS关闭时才释放,这样就不会出现上面问题,并且也可以做到无论有多少客户端都只有一个连接。
多谢大家!
另:
如何池化?在代码中要如何做,谁能讲得详细一点?
 
我非常贊同 PROMAN 觀點﹐池化是解決途徑之一
 
在要服務端建立共享池才可以,方法一(效果不太好):
class procedure TProviders.UpdateRegistry(Register: Boolean;
const ClassID, ProgID: string);
begin
if Register then
begin
inherited UpdateRegistry(Register, ClassID, ProgID);
EnableSpooling(ClassID);//不知道對不對,好久沒有搞三層
EnableSocketTransport(ClassID);
EnableWebTransport(ClassID);
end else
begin
DisableSocketTransport(ClassID);
DisableWebTransport(ClassID);
DisableSpooling(ClassID);//不知道對不對,好久沒有搞三層
inherited UpdateRegistry(Register, ClassID, ProgID);
end;
end;

方法二:
Function RegisterClient(ClientID: Integer;
AcctName, DBConnStr, UserID: String;
DepartID: Integer): Boolean;
var SPM: ISharedPropertyGroupManager;
pg: ISharedPropertyGroup;
sp: ISharedProperty;
LockMode, RelMode: Integer;
Exist: WordBool;
pgName: WideString;
begin
SPM := CreateSharedPropertyGroupManager;
pgName := 'AccountInfo:'+sAppName+':'+AcctName;
LockMode := LockSetGet;
RelMode := Process;
pg := SPM.CreatePropertyGroup(pgName, LockMode, RelMode, Exist);
if not Exist then
begin
sp := pg.CreateProperty('AccountName', Exist);
sp.Value := AcctName;
sp := pg.CreateProperty('ConnStr', Exist);
sp.Value := DBConnStr;
end;
pgName := 'ClientInfo:'+sAppName+':'+IntToStr(ClientID);
LockMode := LockSetGet;
RelMode := Process;
pg := SPM.CreatePropertyGroup(pgName, LockMode, RelMode, Exist);
if not Exist then
begin
sp := pg.CreateProperty('AccountName', Exist);
sp.Value := AcctName;
sp := pg.CreateProperty('UserID', Exist);
sp.Value := UserID;
sp := pg.CreateProperty('DepartID', Exist);
sp.Value := DepartID;
end;
Result := true;
end;
 
to hiyaolee:
你那段代碼是什么年代的﹐你有沒有調試過﹖
能否給出所有代碼﹖這叫人不知從何看起﹐不要誤導人家﹗
 
把 ADOConnection 放在一个 DataModule 中而不是 RemoteDataModule 中,然后 RemoteDataModule 中的 DataSet(s) 都连接到 DataModule 中的 ...
 
to Kisber;
这样做不行,若同时有多个用户使用一个套件,不可以共享连接!
 
sorry,前段太忙,很少上DFW,倒把此问题给忘了。
在我的一个套件中有若干组件,其中只有一个组件上面有AdoConnection是专门负责连接到数据库的,其它组件中的所有Dataset都连向此Connection,这样我希望这一个套件在被激活时只会连接数据库一次,其后其它的组件都不需要再进行连接,在C/S结构的程序中这本是一个十分常用的做法。另外在其它组件中,为了以后的扩展,我在onCreate事件中写了一个过程,此过程就是创建一个前面一个“连接组件”的实例,并将这个实例中的Connection赋值给本组件中的所有Dataset.
可是,我没想到的是,MTS中的组件是在调用它其中所定义的方法时才会被创建的,而创建后一定时间就会被释放,而下次调用则又会被创建,这就导致了每调用一个方法,“连接组件”就会被创建一次,也就是上面的那个问题了。大概这就是JIT吧!
为什么我原来要在每一个组件的的onCreate事件中创建一个"连接组件"呢?大家想一想,“连接组件”也是一个MTS的组件,如果不这样做,在调用其它组件的方法时它也许已经被释放了!
不好意思,第一次用MTS,实在是没有办法!
现在的做法,很简单,在套件中我在一个与客户端直接关联的协调对象组件的initilization区中动态生成一个AdoConnection对象并连接到数据库,其它组件可以直接用它,而在finalization区中断开连接并释放,暂时解决了问题!!!
不知哪们还有更好的方法????
多谢楼上几位的回答。
 
后退
顶部