OBDC:連線與連線池
在使用C++訪問資料庫時一定會使用到連線與連線池,下面就以MS SQL Server為例,介紹一下如何使用它們。
目錄
一、連線字串是怎樣定義的?
下面通過一個例子,說明連線字串要如何配置:
Driver={ODBC Driver 17 for SQL Server};Address=tcp:127.0.0.1,1433;Server=\\TestServer;Database=testDB;Uid=guest;Pwd=12345678;language=Simplified Chinese;
- Driver——表示所使用的驅動名稱。本機可使用的驅動可以在“ODBC資料來源” - > “驅動程式”中找到所有可用驅動程式。如果不想自己手動輸入,也可以在“ODBC資料來源” - > “檔案DNS”點選“新增”,選中想要使用的驅動,點選“高階”,就可以看到可以複製的驅動名稱。
- Address——表示要連線的資料庫網路地址。一般包格式:
Address=[protocol:]Address[,port |\pipe\pipename]
協議可以是 tcp (TCP/IP)、 lpc (共享記憶體)或 np (命名管道) - Server——表示資料庫例項名。一般包格式:
Server=
協議可以是 tcp (TCP/IP)、 lpc (共享記憶體)或 np (命名管道) - Database——表示資料庫名
- Uid——表示登入使用者名稱
- Pwd——表示登入使用者密碼
- Language——表示資料庫伺服器使用的語言(可選)
其中Address的內容可以和到Server中。
二、如何使用連線字串?
SQLHENV henv = NULL; SQLHDBC hdbc = NULL; SQLRETURN retcode; # 分配環境控制代碼 retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv); # 使用環境控制代碼設定驅動版本號 retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER*)SQL_OV_ODBC3, 0); # 分配連線控制代碼 retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc); # 設定連線登入超時 retcode = SQLSetConnectAttr(hdbc, SQL_LOGIN_TIMEOUT, (SQLPOINTER)5, 0); SQLWCHAR outstr[1024]; SQLSMALLINT outstrlen; retcode = SQLDriverConnect(hdbc, NULL, (SQLWCHAR*) L"Driver={ODBC Driver 17 for SQL Server};Server=127.0.0.1,1433\\TestServer;Database=testDB;Uid=sa;Pwd=12345678;", SQL_NTS, outstr, sizeof(outstr), &outstrlen, SQL_DRIVER_NOPROMPT);
SQLDriverConnect函式的定義如下:
SQLRETURN SQLDriverConnect(
SQLHDBC ConnectionHandle,
SQLHWND WindowHandle,
SQLCHAR * InConnectionString,
SQLSMALLINT StringLength1,
SQLCHAR * OutConnectionString,
SQLSMALLINT BufferLength,
SQLSMALLINT * StringLength2Ptr,
SQLUSMALLINT DriverCompletion);
InConnectionString——表示連線字串。如果StringLength1的值為SQL_NTS,則InConnectionString必須以'\0'結尾,否則,StringLength1要指定InConnectionString的長度。
OutConnectionString——表示InConnectionString被解析完成後最終生成的連線字串。
BufferLength——表示用於存放OutConnectionString的緩衝區大小。
StringLength2Ptr——表示最終生成的OutConnectionString的長度。
三、連線中需要設定哪些屬性?
設定連線屬性的函式如下:
SQLRETURN SQLSetConnectAttr(
SQLHDBC ConnectionHandle,
SQLINTEGER Attribute,
SQLPOINTER ValuePtr,
SQLINTEGER StringLength);
常用連線屬性、屬性型別、可選屬性引數:
SQL_ATTR_CONNECTION_TIMEOUT An SQLUINTEGER value
SQL_ATTR_LOGIN_TIMEOUT An SQLUINTEGER value
SQL_ATTR_PACKET_SIZE An SQLUINTEGER value
SQL_ATTR_ACCESS_MODE An SQLUINTEGER value. if a data source is read-only or read-write.
SQL_MODE_READ_ONLY
SQL_MODE_READ_WRITE default
SQL_ATTR_AUTOCOMMIT A SQLUINTEGER value
SQL_AUTOCOMMIT_ON default
SQL_AUTOCOMMIT_OFF
SQL_ATTR_TXN_ISOLATION A 32-bit bitmask
SQL_TXN_READ_UNCOMMITTED
SQL_TXN_READ_COMMITTED
SQL_TXN_REPEATABLE_READ
SQL_TXN_SERIALIZABLE
SQL_ATTR_CONNECTION_DEAD A read-only SQLUINTEGER value
SQL_CD_TRUE
SQL_CD_FALSE
這些屬性的具體說明及其它屬性的說明,請查閱參考文件。
四、如何獲取連線的屬性值?
可以通過SQLGetConnectAttr 函式獲取連線的屬性值,下面舉例說明:
SQLUINTEGER getAutoCommit(SQLHDBC hdbc) {
SQLUINTEGER autoCommit;
SQLRETURN retCode = SQLGetConnectAttr(hdbc, SQL_ATTR_AUTOCOMMIT, (SQLPOINTER)&autoCommit, sizeof(autoCommit), NULL);
return autoCommit;
};
SQLUINTEGER getTxnIsolation(SQLHDBC hdbc) {
SQLUINTEGER txnIsolation;
SQLRETURN retCode = SQLGetConnectAttr(hdbc, SQL_ATTR_TXN_ISOLATION, (SQLPOINTER)&txnIsolation, sizeof(txnIsolation), NULL);
return txnIsolation;
};
五、如何設定連線池
設定連線池需要用到的環境屬性及其可選的值:
SQL_ATTR_CONNECTION_POOLING
SQL_CP_ONE_PER_HENV
SQL_CP_ONE_PER_DRIVER
SQL_CP_DEFAULT = SQL_CP_OFF
SQL_CP_OFF
SQL_CP_ONE_PER_HENV——表示每個環境對應一個池。這個池中可以有不同驅動的連線
SQL_CP_ONE_PER_DRIVER——表示每個驅動對應一個池。這個池中可以有從不同環境中建立的連線,只要驅動相同就會放到一個池中。
SQLHENV henv = SQL_NULL_HENV;
SQLRETURN retCode;
retCode = SQLSetEnvAttr(SQL_NULL_HANDLE, SQL_ATTR_CONNECTION_POOLING, (SQLPOINTER*)SQL_CP_ONE_PER_HENV, 0);
retCode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);
注意,連線池屬性必須在環境控制代碼建立前設定。
六、如何從連線池中取出連線,如何釋放連線池中的連線?
從連線池中取出連線的方式跟建立單個連線的方式相同,都是先設定連線屬性再建立連線(有些連線屬性可能在建立連線後設置)
SQLHDBC hdbc = SQL_NULL_HDBC;
SQLRETURN retCode;
retCode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);
retCode = SQLSetConnectAttr(hdbc, SQL_ATTR_CONNECTION_TIMEOUT, (SQLPOINTER)5, 0);
retCode = SQLSetConnectAttr(hdbc, SQL_ATTR_LOGIN_TIMEOUT, (SQLPOINTER)5, 0);
retCode = SQLSetConnectAttr(hdbc, SQL_ATTR_ACCESS_MODE, (SQLPOINTER)accessMode, 0);
retCode = SQLSetConnectAttr(hdbc, SQL_ATTR_TXN_ISOLATION, (SQLPOINTER)txnIsolationLevel, 0);
retCode = SQLSetConnectAttr(hdbc, SQL_ATTR_AUTOCOMMIT, (SQLPOINTER)autoCommit, 0);
SQLWCHAR outConnStr[1024];
SQLSMALLINT outConnLen;
retCode = SQLDriverConnect(hdbc, NULL, (SQLWCHAR*)connStr.c_str(), SQL_NTS, outConnStr, sizeof(outConnStr), &outConnLen, SQL_DRIVER_NOPROMPT);
釋放連線池中的連線跟釋放單個連線使用的API相同,不同之處在於相同API背後實現的機制不同:連線池中的連線釋放後會返回連線池,後續可再取出使用,而單個連線釋放後是斷開連線。
if (hdbc != SQL_NULL_HDBC) {
SQLDisconnect(hdbc);
SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
hdbc = SQL_NULL_HDBC;
}
參考
將連線字串關鍵字用於 SQL Server Native Client
SQLDriverConnect 函式
SQLSetConnectAttr 函式
ODBC連線池配置:
Pooling in the Microsoft Data Access Components
關於連線池環境如何建立,請查閱“SQLAllocHandle 函式”
關於連線池的配置引數的介紹,請查閱“SQLSetEnvAttr 函式”