我应该如何在HTTP TIdServerContext线程中实现ADO连接?

时间:2014-08-07 02:24:09

标签: multithreading delphi ado indy10 httpserver

我一直在处理TIdHTTPServer事件的HTTP服务器(OnCommandGet)。我刚刚创建了TIdServerContext的继承对象,并重写了它的构造函数和析构函数。现在,我想将我的数据库连接从先前的自定义会话对象移动到此上下文线程中。服务器的KeepAlive属性已启用。

目标是回收在每个会话中实现的数据库连接。目前,每个请求都会产生一个新的ADO连接,我想避免这种情况。我理解KeepAlive并不一定意味着整个登录/注销会话,而只是维持一个持续的连接以节省资源。

我的问题是,我应该如何利用我继承的TIdServerContext对象来维护自己的一致数据库连接(TADOConnection) - 可以使用(在COM规则中CoInitialize) )每个请求?

我假设我放在OnCommandGet事件处理程序中的任何代码都在与继承的TIdServerContext相同的线程上下文中运行 - 这是正确的吗?本质上意味着... TIdServerContext.OnRunTIdHTTPServer.OnCommandGet在同一个线程和COM中的使用是否安全?

1 个答案:

答案 0 :(得分:2)

OnCommandGet确实在TIdServerContext运行的同一个线程中运行。

您无法分配自己的OnRun处理程序,因为TIdCustomTCPServer已使用该事件触发其DoExecute()方法,TIdHTTPServer覆盖该方法以触发其OnCommamd...事件

如果要在来自同一客户端的多个请求中重用数据库对象,可以初始化COM并在OnConnect事件中创建数据库对象,并释放数据库对象并在OnDisconnect事件中释放COM。但是,如果客户端在每个请求上请求keepalive,则使用这些事件只会有所帮助,这不是保证。 TIdHTTPServer.KeepAlive属性仅允许服务器在需要时使用keepalive,它不会强制客户端请求它们。如果没有被要求,每个请求都会触发自己的一对OnConnect/OnDisconnect事件。

ADO是基于COM的,因此它具有线程关联性。此外,COM应该每个线程只初始化一次。因此,最好在线程启动时初始化COM并创建数据库对象,并在线程结束时释放数据库对象并释放COM。默认情况下,Indy服务器为每个客户端连接使用一个新线程,因此通过切换到此模型,您仍然可以从使用OnConnect/OnDisconnect事件的类似行为中受益。无论客户端是否使用keepalive,效果都是一样的。

但是,此模型为您提供了更大的灵活性,因为现在您可以在服务器中启用线程池(通过将TIdSchedulerOfThreadPool分配给TIdHTTPServer.Scheduler属性),然后可以重用DB对象跨越多个客户端连接,随着时间的推移使用相同的线程。

TIdThreadWithTask派生一个新类,覆盖其BeforeExecute()方法以初始化COM并创建数据库对象,并覆盖其AfterExecute()方法以释放数据库对象(s )并释放COM。将此类分配给调度程序的ThreadClass属性。

要访问OnCommand...事件中的数据库对象,请将AContext.Yarn属性强制转换为TIdYarnOfThread,然后将其Thread属性强制转换为派生类,然后您可以根据需要访问其成员。

您仍然可以派生自定义TIdServerContext类来处理每个客户端数据(Indy不实现上下文池),并根据需要在每个请求的基础上使用数据库对象。只需将DB对象创建/销毁与上下文类分开。