通過OLEDB讀取SQLSERVER數據庫的使用經驗
最近在寫一個用OLEDB從SQLSERVER數據庫讀取數據的VC程序
特將使用的經驗總結一下方便未知使用之者
1、首先建立數據庫連接問題:
你可以使用以前的CoCreateInstance 建立數據庫初始化對象,如下:
CoCreateInstance(_clsid, NULL, CLSCTX_INPROC_SERVER,
IID_IDBInitialize, (void**)&_pDBInit);
但這是一種過時的打開方法,在此基礎上建立的數據庫連接對象會有很多數據庫屬性都不會被支持的
微軟建議的做法是應該使用IDataInitialize 或者 IDBPromptInitialize 打開 ,如下
hr = CoCreateInstance(CLSID_MSDAINITIALIZE, NULL, CLSCTX_INPROC_SERVER, IID_IDataInitialize, (void**)&_pIDataInitialize);
hr = _pIDataInitialize->CreateDBInstance(_clsid, NULL, CLSCTX_INPROC_SERVER, NULL, IID_IDBInitialize, (IUnknown**)&_pDBInit);
這樣的方法建立的數據實例不僅可以利用一些比較新的屬性,並且還支持數據連接池
2、數據連接池的問題:
如果你用以前的那種方法打開的數據庫連接是需要自己實現連接池的,而後者是自動支持數據連接池,但主要如下事項:
1、要釋放所有的接口指針,要記得隨時隨地release,不然它會認爲你還存在引用,就不會自動服用連接了,如下:
_pICT ->SetCommandText(DBGUID_DBSQL, t);
。。。。
if(_pICT) _pICT->Release();
2、在釋放數據庫連接對象時不要調用 Uninitialize 方法,如果調用該方法,數據庫連接池會物理上把連接釋放,這樣造成連接不能複用,如下
int C_DB::CloseDB(){
if( _pDBInit ){
/*
爲了連接池複用,不要調用Uninitialize()方法
*/
//_pDBInit->Uninitialize()
_pDBInit->Release();
}
return 0;
}
3、連接複用問題:
要想知道連接是否被複用,可以通過SQLSERVER後臺啓用SQL監視器,查看日誌信息,如果出現reset conection, 則表示複用連接成功了
4、數據快速讀取問題:
由於程序是實現一次性把所有數據讀取到本地,故在打開記錄集時,要設置從客戶端遊標,如果時非客戶端遊標,讀取速度會受到限制
通過SQLSERVER後臺的監視器就可以看到,如果時服務器遊標,每次通過API讀取數據時都會和服務器通訊,產生不必要的開銷
想知道是否已經設置從客戶端遊標,只要從監視器沒有看到FETCH語句存在就表示OK了
可以通過設置記錄集 DBPROP_CLIENTCURSOR 屬性實現以客戶端遊標方式打開記錄集,如下
_p[1].dwPropertyID = DBPROP_CLIENTCURSOR;
_p[1].dwOptions = DBPROPOPTIONS_REQUIRED;
_p[1].dwStatus = 0;
VariantInit (&_p[1].vValue);
_p[1].vValue.vt = VT_BOOL;
_p[1].vValue.boolVal = VARIANT_TRUE;
5、一次性獲得N條記錄問題:
默認情況下,打開記錄集時只允許一條一條記錄的獲取,如果想一次獲得N條記錄,需要在打開記錄集時設置DBPROP_MAXOPENROWS屬性:
_p[0].dwPropertyID = DBPROP_MAXOPENROWS;
_p[0].dwOptions = DBPROPOPTIONS_REQUIRED;
_p[0].dwStatus = 0;
VariantInit (&_p[0].vValue);
_p[0].vValue.vt = VT_I4;
_p[0].vValue.intVal=0;
上面代碼設置DBPROP_MAXOPENROWS屬性爲0,表示沒有限制,當前並不代碼實際應用上你使用上沒有限制,比如你一下子獲取幾十萬條記錄,這樣資源本身就會限制你,所以在調用API獲得記錄時要記得檢查結果
6、數據連續獲取問題:
在通過API獲得記錄時,如果沒有釋放記錄集,再次獲取記錄的時候會報錯,如下代碼
hr=pIRS->GetNextRows( NULL, 0, PER_RECORD_NUM, & tmpRows, &parrRows );
....
hr=pIRS->GetNextRows( NULL, 0, PER_RECORD_NUM, & tmpRows, &parrRows );
這樣會報錯,所以需要在打開記錄集時設置DBPROP_CANHOLDROWS,如下
_p[1].dwPropertyID = DBPROP_CANHOLDROWS;
_p[1].dwOptions = DBPROPOPTIONS_REQUIRED;
_p[1].dwStatus = 0;
VariantInit (&_p[1].vValue);
_p[1].vValue.vt = VT_BOOL;
_p[1].vValue.boolVal = VARIANT_TRUE;
不然你只能實在的獲得記錄,然後在釋放記錄了,如下
hr=pIRS->GetNextRows( NULL, 0, PER_RECORD_NUM, & tmpRows, &parrRows );
....
pIRS -> ReleaseRows(tmpRows, arrRows, NULL, NULL, NULL);
...
hr=pIRS->GetNextRows( NULL, 0, PER_RECORD_NUM, & tmpRows, &parrRows );
7、再隨便寫上第7條把
在CoCreateInstance(_clsid...)語句中需要提供clsid,下面我舉2個例子來說明獲得SQLSERVER和ACCESS的CLSID
CLSIDFromProgID(L"SQLOLEDB", &_clsid);
CLSIDFromProgID(L"Microsoft.Jet.OLEDB.4.0", &_clsid);
好了,寫完了,希望能對你有所幫助