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ですが、これはMSSQLServerに固有です。

通常、ステートメントハンドルが失敗することはないと思いますが、stmtを実行するだけで失敗した場合は、接続が切断されていると想定し、再接続して再準備しますか?

接続が切断された場合でも、さまざまなハンドルに対してSQLFreeHandleを呼び出す必要があります。

于 2012-07-12T13:54:44.617 に答える