连接都会消耗服务器上的资源,大招开启临时断开SQL连接

2022-04-07 19:34:19 浏览数 (1)

译者:Fbilo

你学到的访问远程数据的首要原则之一,是限制连接的数量。每个到后台数据库的连接都会消耗服务器上的资源,而并发连接的数量又可能受到授权协议的限制。另一方面,接连的关闭和重新打开连接要求额外的代码和时间花费。 VFP 引入了两个改动来帮助最小化你所需要的连接的数量。SQLCONNECT()可以使用一个已有的共享连接,同时你可以通过指定一个状态句柄(statement handle)代替 cConnectionName 参数,来使用一个已有的共享连接去打开一个远程视图。在我们的应用程序中,我们通常使用单个基于用户登录信息的共享连接,并在该应用程序的生命周期内使用该连接。

然而,有些情况下你也许需要短时间的打开一个额外的连接。例如,你也许需要周期性的从另一个数据库去返回数据、或者使用一个独立的连接来执行一个运行时间较长的查询。过去,每次你想要再次连接到远程数据源的时候,你需要执行 SQLCONNECT() 或者 SQLSTRINGCONNECT(),每次重新连接后你会接受到一个新的状态句柄。

新的 SQLIDLEDISCONNECT() 函数临时的断开来自远程数据库的连接,但会保留 VFP 的状态句柄和原始的连接参数。它的语法是:

SQLIDLEDISCONNECT( nStatementHandle )

如果你的应用程序试图去再次使用这个状态句柄,VFP 会使用原始的连接参数去重新连接到远程数据库。如果不能建立连接,会发生1526号错误(“Connectivity error”)。作为结果,你可以在任何时候重新使用这个连接而不需要担心它是否仍然可用的问题,也不需要再次执行 SQLCONNECT() 或者 SQLSTRINGCONNECT()。

注意传递给 SQLIDLEDISCONNECT()的是一个状态句柄。从 VFP 8 开始,SQL 函数转为使用状态句柄(statement handle)而不是连接句柄(connection handle)。一个连接句柄代表对一个数据库引擎的一个惟一的连接。如果该连接被标记为共享,那么它可以在一个应用程序中被多个状态句柄所使用。

SQLIDLEDISCONNECT()断开状态句柄的连接,但不会释放对数据库服务器的连接,直到它的所有状态句柄都被释放为止。在调用 SQLIDLEDISCONNECT() 后,你可以使用 SQLGETPROP() 来判断该连接是否已经被释放。如果状态句柄被断开,则 ODBChstmt 属性为0;如果到后台的连接已经被释放,则 ODBChdbc 属性为0(参见本章后面的“判断哪些连接被打开了”一节以了解一种判断哪些状态句柄共享一个指定连接的途径)。

SQLIDLEDISCONNECT() 如果成功则返回1,如果它不能断开则返回-1。如果一个连接正在忙着执行一个查询、或者连接正处于手动事务模式中的话,你就不能断开该连接。

这里是一个演示两个共享连接如何变得空闲、然后自动重新连接到数据库的例子。它会在每一个阶段为每个连接显示语句和连接句柄。中间还通过抢占一开始被分配给前两个连接的连接句柄来打开了第三个非共享连接。然后当那两个空闲的连接重新连接的时候它们会得到一个新的连接句柄。这个示例还演示了当一个连接上的所有连接句柄都变为空闲了的时候,对数据库的物理连接(由连接句柄所代表)是如何被放弃的。

代码语言:javascript复制
CLOSE DATABASES ALL
SET TALK OFF
CLEAR

LOCAL lcDir, lcDbc, lcConnStr, lnConn1, lnConn2, lnConn3, ;
  lnHandles, laHandles[1], n

*-- 使用 ODBC 连接到 Tastrade 示例数据库

lcDir = HOME(2)   "tastradedata"
lcDbc = lcDir   "tastrade.dbc"

IF ! FILE(lcDbc)
  MESSAGEBOX("The VFP sample database Tastrade.dbc cannot be found in " ;
    lcDir, 16, "Sorry, I need to use the Tastrade sample database.")
  RETURN
ENDIF

*-- 打开到 Tastrade 数据库的第一个连接,将之标记为可共享
lcConnStr = [Driver={Microsoft Visual FoxPro Driver};UID=;PWD=;SourceDB=]   ;
   lcDbc   [;SourceType=DBC;Exclusive=No;BackgroundFetch=No;Collate=Machine;]

lnConn1 = SQLSTRINGCONNECT(lcConnStr, .T.)

IF lnConn1 < 1
  MESSAGEBOX("Could not connect to Tastrade.dbc. Reason: "   MESSAGE(), ;
    16, "Sorry, could not connect")
  RETURN
ENDIF

 *-- 在同一个连接上打开第二个状态句柄
lnConn2 = SQLCONNECT(lnConn1)

IF lnConn2 < 1
  MESSAGEBOX("Could not connect to Tastrade.dbc. Reason: "   MESSAGE(), ;
    16, "Sorry, could not connect")
  SQLDISCONNECT(lnConn1)
  RETURN
ENDIF

DO showhandles WITH "Opened 2 connections", lnConn1, lnConn2

*-- 将第二个连接句柄设置为空闲
SQLIDLEDISCONNECT(lnConn2)
DO showhandles WITH "Connection 2 idled", lnConn1, lnConn2

*-- 将第二个连接句柄设置为空闲
SQLIDLEDISCONNECT(lnConn1)
DO showhandles WITH "Connection 1 idled", lnConn1, lnConn2

*-- 打开另一个到数据库的连接句柄。
* 这么做是为了演示重新连接一个空闲连接,也许会导致建立一个对数据库的新连接
lnConn3 = SQLSTRINGCONNECT(lcConnStr)
? "Connection 3 was assigned ODBC connection " ;
    TRANSFORM(SQLGETPROP(lnConn3,"ODBChdbc"))
?

*-- 在空闲状态句柄2上执行一个查询
SQLEXEC(lnConn2, "SELECT * FROM customer")
DO showhandles WITH "Executed query on connection 2", lnConn1, lnConn2

*-- 在空闲连接1上执行一个查询
SQLEXEC(lnConn1, "SELECT * FROM customer")
DO showhandles WITH "Executed query on connection 1", lnConn1, lnConn2

*-- 使用新的 ASQLHANDLES() 函数来关闭所有打开了的连接
lnHandles = ASQLHANDLES(laHandles)

FOR N = 1 TO lnHandles
  SQLDISCONNECT(laHandles[n])
NEXT

RETURN

**********************************************
PROCEDURE showhandles(tcMsg, tnConn1, tnConn2)
**********************************************
LOCAL lnCHnd1, lnCHnd2, lnSHnd1, lnSHnd2

*-- 为每个连接取得连接句柄
lnCHnd1 = SQLGETPROP(tnConn1,"ODBChdbc")
lnCHnd2 = SQLGETPROP(tnConn2,"ODBChdbc")

*-- 为每个连接取得状态句柄
lnSHnd1 = SQLGETPROP(tnConn1,"ODBChstmt")
lnSHnd2 = SQLGETPROP(tnConn2,"ODBChstmt")

? tcMsg
? "Connection 1: ODBC connection = "   TRANSFORM(lnCHnd1) ;
    ", ODBC statement = "   TRANSFORM(lnSHnd1)

? "Connection 2: ODBC connection = "   TRANSFORM(lnCHnd2) ;
    ", ODBC statement = "   TRANSFORM(lnSHnd2)
?

RETURN

你将看到如下的结果(在你系统上的数字也许不同,但基本的结果应该是一样的):

代码语言:javascript复制
Opened 2 connections
Connection 1: ODBC connection = 29562256, ODBC statement = 29564872
Connection 2: ODBC connection = 29562256, ODBC statement = 29567904

Connection 2 idled
Connection 1: ODBC connection = 29562256, ODBC statement = 29564872
Connection 2: ODBC connection = 29562256, ODBC statement = 0

Connection 1 idled
Connection 1: ODBC connection = 0, ODBC statement = 0
Connection 2: ODBC connection = 0, ODBC statement = 0

Connection 3 was assigned Connection handle 29562256

Executed query on connection 2
Connection 1: ODBC connection = 29568920, ODBC statement = 0
Connection 2: ODBC connection = 29568920, ODBC statement = 29564800
Executed query on connection 1
Connection 1: ODBC connection = 29568920, ODBC statement = 29571312
Connection 2: ODBC connection = 29568920, ODBC statement = 29564800

0 人点赞