Delphi 如何在IdhttpServer上实现长时间运行的查询?
在IdHttpServer上实现长时间运行查询的好方法是什么。我已经写了简单的逻辑来做到这一点,请建议更好的方法来达到同样的效果,因为我正在努力与它的性能。 我使用D2010和Indy 10.5.8来实现目标,还建议如果我们经常从会话中检索值,这会是资源密集型的吗Delphi 如何在IdhttpServer上实现长时间运行的查询?,delphi,delphi-2010,indy10,Delphi,Delphi 2010,Indy10,在IdHttpServer上实现长时间运行查询的好方法是什么。我已经写了简单的逻辑来做到这一点,请建议更好的方法来达到同样的效果,因为我正在努力与它的性能。 我使用D2010和Indy 10.5.8来实现目标,还建议如果我们经常从会话中检索值,这会是资源密集型的吗 procedure TForm1.ServerCommandGet(AContext: TIdContext; ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPRes
procedure TForm1.ServerCommandGet(AContext: TIdContext;
ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
var
SessionObj : TSessionData;
begin
if ARequestInfo.Document = 'EXECUTEQUERY' then
begin
if not Assigned(ARequestInfo.Session.Content) then
begin
SessionObj := TSessionData.Create;
ARequestInfo.Session.Content.AddObject('U_SESSION', SessionObj);
SessionObj.RunLongQuery;
end;
end;
if ARequestInfo.Document = 'GETDATA' then
begin
SessionObj := TSessionData(ARequestInfo.Session.Content.Objects[ ARequestInfo.Session.Content.IndexOf('U_SESSION')]);
if SessionObj.GetQueryStat = Done then
begin
AResponseInfo.ContentStream.CopyFrom(SessionObj.GetMemStream, SessionObj.GetMemStream.Size);
SessionObj.GetMemStream.Clear;
AResponseInfo.ResponseNo := 200;
end else if SessionObj.GetQueryStat = Error then
AResponseInfo.ResponseNo := 500
else AResponseInfo.ResponseNo := 102;
end;
end;
procedure TForm1.ServerSessionEnd(Sender: TIdHTTPSession);
begin
TSessionData(Sender.Content.Objects[ Sender.Content.IndexOf('U_SESSION')]).Free;
end;
{ TProcessQuery }
constructor TProcessQuery.Create;
begin
myConn := TMyConnection.Create(nil);
myConn.LoginPrompt := False;
myConn.UserName := 'UserName';
myConn.Password := 'Password';
myConn.Server := 'Host';
myConn.Database := 'DBName';
myConn.Connected := True;
myQuery := TMyQuery.Create(nil);
myQuery.Unidirectional := True;
myQuery.Options.CreateConnection := False;
myQuery.Connection := myConn;
Fstat := None;
Fstream := TMemoryStream.Create;
end;
destructor TProcessQuery.Destroy;
begin
if Assigned(myConn) then begin
myConn.Close;
myConn.Disconnect;
FreeAndNil(myConn);
end;
end;
procedure TProcessQuery.ExecuteQuery;
begin
Status := Started;
myQuery.SQL.Text := '<Some Query>';
myQuery.Open;
try
try
while not myQuery.Eof do
begin
Status := Inprogress;
//Add to FStream which would be returned to user.
end;
except
on Exception do
Status := Error;
end;
finally
myQuery.Close;
end;
end;
{ TSessionData }
constructor TSessionData.Create;
begin
FProcessQuery := TProcessQuery.Create;
end;
function TSessionData.GetMemStream: TMemoryStream;
begin
result := FProcessQuery.Fstream;
end;
function TSessionData.GetQueryStat: TStatus;
begin
result := FProcessQuery.Status;
end;
procedure TSessionData.RunLongQuery;
begin
FProcessQuery.ExecuteQuery
end;
过程TForm1.ServerCommandGet(AContext:TIdContext;
ARequestInfo:TIdHTTPRequestInfo;AResponseInfo:TIdHTTPResponseInfo);
变量
会话BJ:会话数据;
开始
如果ARequestInfo.Document='EXECUTEQUERY',则
开始
如果未分配(ARequestInfo.Session.Content),则
开始
SessionObj:=TSessionData.Create;
ARequestInfo.Session.Content.AddObject('U_Session',SessionObj);
SessionObj.RunLongQuery;
结束;
结束;
如果ARequestInfo.Document='GETDATA',则
开始
SessionObj:=TSessionData(ARequestInfo.Session.Content.Objects[ARequestInfo.Session.Content.IndexOf('U_Session'));
如果SessionObj.GetQueryStat=Done,则
开始
AResponseInfo.ContentStream.CopyFrom(SessionObj.GetMemStream,SessionObj.GetMemStream.Size);
SessionObj.GetMemStream.Clear;
AResponseInfo.ResponseNo:=200;
如果SessionObj.GetQueryStat=错误,则结束else
AResponseInfo.ResponseNo:=500
else AResponseInfo.ResponseNo:=102;
结束;
结束;
过程TForm1.ServerSessionEnd(发送方:TIdHTTPSession);
开始
TSessionData(Sender.Content.Objects[Sender.Content.IndexOf('U_SESSION')).Free;
结束;
{TProcessQuery}
构造函数TProcessQuery.Create;
开始
myConn:=TMyConnection.Create(nil);
myConn.LoginPrompt:=False;
myConn.UserName:=“用户名”;
myConn.Password:=“密码”;
myConn.Server:=“主机”;
myConn.Database:=“DBName”;
myConn.Connected:=真;
myQuery:=TMyQuery.Create(nil);
myQuery.单向:=True;
myQuery.Options.CreateConnection:=False;
myQuery.Connection:=myConn;
Fstat:=无;
Fstream:=TMemoryStream.Create;
结束;
析构函数TProcessQuery.Destroy;
开始
如果已分配(myConn),则开始
麦康.关闭;
断开连接;
FreeAndNil(myConn);
结束;
结束;
过程TProcessQuery.ExecuteQuery;
开始
状态:=已启动;
myQuery.SQL.Text:='';
myQuery.Open;
尝试
尝试
而不是myQuery.Eof do
开始
状态:=正在进行中;
//添加到将返回给用户的FStream。
结束;
除了
例外情况
状态:=错误;
结束;
最后
myQuery.Close;
结束;
结束;
{TSessionData}
构造函数TSessionData.Create;
开始
FProcessQuery:=TProcessQuery.Create;
结束;
函数TSessionData.GetMemStream:TMemoryStream;
开始
结果:=FProcessQuery.Fstream;
结束;
函数TSessionData.GetQueryStat:TStatus;
开始
结果:=FProcessQuery.Status;
结束;
程序TSessionData.RunLongQuery;
开始
FProcessQuery.ExecuteQuery
结束;
您正在ServerCommandGet()的上下文中运行实际查询,因此在查询完成之前,客户端不会收到回复。对于您正在尝试的内容,您需要将查询移动到它自己的线程,并让ServerCommandGet()
退出,以便客户端获得答复并可以继续,从而释放它来发送后续的GETDATA
请求。在ServerSessionEnd()
中,如果查询线程仍在运行,则必须终止该线程,并释放TSessionData
对象
您的代码还存在一些其他问题
ServerCommandGet()
正在检查是否未分配(ARequestInfo.Session.Content)
然后在ARequestInfo.Session.Content
为零时调用ARequestInfo.Session.Content.AddObject()。我没有看到任何创建ARequestInfo.Session.Content
对象的代码
如果客户端发出多个EXECUTEQUERY
请求,您将使用相同的名称“U\U Session”将它们全部存储在AResponseInfo.Session.Content
中GETDATA
将只返回它找到的第一个查询的结果,ServerSessionEnd()
只释放它找到的第一个查询。因此,为每个查询指定一个唯一的名称并将其发送回客户端,以便它可以将其包含在GETDATA
中,并使ServerSessionEnd()
在整个Sender.Content
中循环,或者不允许在同一HTTP会话中进行多个查询。如果客户机在上一个查询仍处于活动状态时发出新的EXECUTEQUERY
,请在启动新查询之前终止上一个查询
当客户机发出GETDATA
时,代码需要考虑请求的查询可能不存在,例如它以前是否已过期并由ServerSessionEnd()释放。另外,如果查询确实存在并且已完成,则调用的是AResponseInfo.ContentStream.CopyFrom()
,但调用ServerCommandGet()
时AResponseInfo.ContentStream
为零。您负责提供自己的ContentStream
对象。因此,要么拥有TSessionData
的内存流的所有权并将其分配为AresOnSeInfo.ContentStream
对象,要么创建一个新的TMemoryStream
复制到其中,然后将其分配为AresOnSeInfo.ContentStream
对象。无论哪种方式,TIdHTTPServer
都会在将AresOnSeInfo.ContentStream发送到客户端后释放它。您正在ServerCommandGet()
的上下文中运行实际的查询,因此客户端在查询完成之前不会收到回复。对于您正在尝试的内容,您需要将查询移动到它自己的线程,并让ServerCommandGet()
退出,以便客户端获得答复并可以继续,从而释放它来发送后续的GETDATA
请求。在ServerSessionEnd()
中,必须终止查询线程