0

我们创建并缓存使用SQLDriverConnect创建的 ODBC 连接;我们发现了连接丢失的情况......准备好的语句停止工作,等等。

我没有看到一个明显的功能来测试连接/语句是否有效,或者重置/重新创建连接,这似乎是一种相当常见的模式。谁能建议如何最好地实施?

这个答案是相同的,这也是正确的解决方案吗?如果是这样,是否有任何巧妙的方法可以“重新启动”现有语句以使用新连接?如果发现连接已死,是否还需要释放它?

4

1 回答 1

0

在我看来,对于 SQL_ATTR_CONNECTION_DEAD 是否可以在您拨打要求它处于活动状态的呼叫之前测试连接是否仍然活动,一直存在一些混淆。这是基于许多 ODBC 驱动程序的使用,包括我编写的驱动程序,我怀疑它们可能都以不同的方式实现它。

在帖子中,您参考了尼克的答案(SQL_ATTR_CONNECTION_DEAD)不适用于我可以访问的许多驱动程序:

#include <stdio.h>
#include <sql.h>
#include <sqlext.h>
#include <stdlib.h>

static void extract_error(
    char *fn,
    SQLHANDLE handle,
    SQLSMALLINT type);

main() {
    SQLHENV henv;
    SQLHDBC hdbc;
    SQLHSTMT hstmt;
    SQLCHAR outstr[1024];
    SQLSMALLINT         outstr_len;
    SQLRETURN ret;
    SQLINTEGER dead;

    SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);
    SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (void *) SQL_OV_ODBC3, 0);
    SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);
    ret = SQLDriverConnect(hdbc, (void *)0, "DSN=xx;UID=xx;PWD=xx", SQL_NTS,
                           outstr, sizeof(outstr), &outstr_len,
                           SQL_DRIVER_COMPLETE);
    if (!SQL_SUCCEEDED(ret)) {
        extract_error("SQLDriverConnect", hdbc, SQL_HANDLE_DBC);
        exit(1);
    }

    SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);
    ret = SQLPrepare(hstmt, "select 123", SQL_NTS);
    if (!SQL_SUCCEEDED(ret)) {
        extract_error("SQLPrepare", hstmt, SQL_HANDLE_STMT);
        exit(1);
    }

    ret = SQLExecute(hstmt);
    if (!SQL_SUCCEEDED(ret)) {
        extract_error("SQLExecute", hstmt, SQL_HANDLE_STMT);
        exit(1);
    }

    sleep(120);

    SQLGetConnectAttr(hdbc, SQL_ATTR_CONNECTION_DEAD, &dead, 0, NULL);
    printf ("dead=%ld\n", dead);

    ret = SQLExecute(hstmt);
    if (!SQL_SUCCEEDED(ret)) {
        extract_error("SQLExecute", hstmt, SQL_HANDLE_STMT);
    }
    SQLGetConnectAttr(hdbc, SQL_ATTR_CONNECTION_DEAD, &dead, 0, NULL);
    printf ("dead=%ld\n", dead);


}


static void extract_error(
    char *fn,
    SQLHANDLE handle,
    SQLSMALLINT type)
{
    SQLINTEGER i = 0, native;
    SQLCHAR state[ 7 ];
    SQLCHAR text[256];
    SQLSMALLINT len;
    int ret;

    fprintf(stderr,
            "\n"
            "The driver reported the following diagnostics whilst running "
            "%s\n\n",
            fn);

    do
    {
        ret = SQLGetDiagRec(type, handle, ++i, state, &native, text,
                            sizeof(text), &len );
        if (SQL_SUCCEEDED(ret))
            printf( "%s:%ld:%ld:%s\n", state, i, native, text );
    }
    while( ret == SQL_SUCCESS );
}

输出有多个驱动程序:

dead=0
# At this point I took the server down
The driver reported the following diagnostics whilst running SQLExecute
08S01:1:0:[SQL Server Driver 10.0][SQL Server]Communication link failure: short write
dead=0

您提到的帖子中指定的另一个选项是 SQL_COPT_SS_CONNECTION_DEAD ,但它特定于 MS SQL Server。

由于我认为您不打算让任何语句句柄失败,通常您不能只运行 stmt 并且如果它失败则假设连接已死并重新连接并重新准备?

如果连接确实死了,您仍然需要为各种句柄调用 SQLFreeHandle。

于 2012-07-12T13:54:44.617 回答