前言:
鄙司原始用的都是ADO来访问数据库,而我现在着手的项目是从我的GPS历史数据库中,取出历时数据的一个接口,一个DLL.用ADO写完之后,测试下来,平均4000条的数据,需要 180 毫秒左右. 包括数据包的排序.领导说有点慢.他是用C#写的.
而后我查找了资料,决定用Native Client OLEDB来试一试. 测试之后,效果还不错.取4000条的数据,只花了50毫秒左右,足足快了三倍.当然这也包括了排序.
鉴于此外加OLEDB资料很少,把我的代码分享出来.
WO 对 OLEDB 进行了简单的封装. 以下是项目的OLEDB部分代码.
//NativeClientOLEDB.h
#pragma once #include <oledb.h>
#include <oledberr.h>
#include <stdio.h>
#include <stddef.h> // for offsetof #include <msdaguid.h>
#include <msdasql.h>
#include <msdasc.h>
#include <sqlncli.h>
#include <string>
//#include "C:\Program Files\Microsoft SQL Server\110\SDK\Include\sqlncli.h" #ifndef _AUTHOR_NAME
#define _AUTHOR_NAME "沈春钟"
#define _CREATE_DATE "2016-05-18"
#define _LIBRARY_TITLE "NativeClientOLEDB"
#define _LIBRARY_DESC "对NaTiveClientOLEDB的封装"
#define _MAINTAIN_CONTACT "SamRichard@live.cn"
#define _MAX_COL_NUM 100
#endif #pragma comment(lib, "sqlncli11.lib") // @type UWORD | 2 byte unsigned integer.
typedef unsigned short UWORD; // @type SDWORD | 4 byte signed integer.
typedef signed long SDWORD; using namespace std; //委托表数据结构体
#pragma pack(push, 1)
class Data
{
//SDWORD SOID_len; // Length of data (not space allocated).
//DWORD SOID_status; // Status of column.
//int SOID_value;
};
#pragma pack(pop) //// How to lay out each column in memory.
//struct COLUMNDATA {
// SDWORD idLen; // Length of data (not space allocated).
// DWORD idStatus; // Status of column.
// int id; // Store data here as a variant.
// SDWORD dateLen;
// DWORD dateStatus;
// char date[21];
//}; class CNativeClientOLEDB
{
public:
CNativeClientOLEDB(void);
~CNativeClientOLEDB(void); public:
//初始化连接
HRESULT Init(CStringW strDataSource, CStringW strUserID, CStringW strPassWD, CStringW strCataLOG);
//不建议用此方式初始化
HRESULT Init(CStringW strConnectionString);
//释放连接
void UnInit(); protected:
//函数申明
virtual void set_bindings();
//设置每列数据列的类型
virtual void SetColType(void);
//设置每列数据列的长度
virtual void SetColLen(void); //bind one by one
void set_bind(DBBINDING &binding, int col, DBBYTEOFFSET len_offset, DBBYTEOFFSET status_offset, DBBYTEOFFSET value_offset, DBLENGTH len, DBTYPE type); void DumpErrorInfo(IUnknown* pObjectWithError, REFIID IID_InterfaceWithError); //HRESULT FastInsertData();
//快速查询数据
HRESULT FastQueryData(CStringW strSql,ULONG& nColNum, IRowset** pIRowset,IAccessor** pIAccessor, HACCESSOR& hAccessor);
//释放RowSet和IAccessor
HRESULT ReleaseRowsetAndIAccessor(IRowset** pIRowset,IAccessor** pIAccessor,const HACCESSOR& hAccessor);
//快速插入数据
HRESULT FastInsertData(CStringW strTable, ULONG& nColNum, IRowsetFastLoad** pIRowsetFastLoad, IAccessor** pIAccessor, HACCESSOR& hAccessor);
//释放RowsetFast和IAccessor
HRESULT ReleaseRowsetFastLoadAndIAccessor(IRowsetFastLoad** pIRowset,IAccessor** pIAccessor,const HACCESSOR& hAccessor); private: // Given an ICommand pointer, properties, and query, a rowsetpointer is returned.
HRESULT DBInitAndConnect(DBPROPSET* rgPropertySets, ULONG ulcPropCount, CLSID clsidProv); // Use to set properties and execute a given query.
HRESULT ExecuteQuery(IDBCreateCommand* pIDBCreateCommand,
WCHAR* pwszQuery,
DBPROPSET* rgPropertySets,
ULONG ulcPropCount,
LONG* pcRowsAffected,
IRowset** ppIRowset,
BOOL fSuccessOnly = TRUE); // Use to set up options for call to IDBInitialize::Initialize.
void SetupOption(DBPROPID PropID, WCHAR *wszVal, DBPROP * pDBProp); // Sets fastload property on/off for session.
HRESULT SetFastLoadProperty(BOOL fSet); public:
//创建会话和命令
HRESULT CreateSessionAndCommand();
//释放会话和命令
HRESULT ReleaseSessionAndCommand();
//设置模式和创建会话
HRESULT SetPropertiesAndCreateSessionAndIOpenRowset(BOOL bFast = TRUE);
//释放会话
HRESULT ReleaseSessionIOpenRowset(); private:
//初始化层
IMalloc* m_pIMalloc;
IDataInitialize* m_pIDataInitialize;
IDBInitialize* m_pIDBInitialize;
// OLE initialized?
BOOL m_bInitialized;
//回话和命令层
IDBCreateSession* m_pIDBSession;
IOpenRowset* m_pIOpenRowset;
ICommand* m_pICommand;
IDBCreateCommand* m_pIDBCreateCommand;
ICommandText* m_pICommandText;
DBID TableID; protected:
//binding数组
DBBINDING m_bindings[_MAX_COL_NUM]; //委托表每列的数据类型
DBTYPEENUM col_type[_MAX_COL_NUM]; //委托表每列的数据长度
DBBYTEOFFSET col_len[_MAX_COL_NUM];
};
//NativeClientOLEDB.cpp
#include "StdAfx.h"
#include "NativeClientOLEDB.h"
#include <time.h>
#include <Base64.h> #define COUNT 10000
#define ROW_SIZE 1000 #define COLUMN_ALIGNVAL 8
#define ROUND_UP(Size, Amount)(((DWORD)(Size) + ((Amount)-1)) & ~((Amount)-1)) const UWORD g_cOPTION = ;
const UWORD MAXPROPERTIES = ;
const ULONG DEFAULT_CBMAXLENGTH = ; CNativeClientOLEDB::CNativeClientOLEDB(void)
{
m_pIMalloc = NULL;
m_pIDBInitialize = NULL;
m_bInitialized = FALSE;
m_pIDBSession = NULL;
m_pIOpenRowset = NULL;
m_pICommand = NULL;
m_pIDBCreateCommand = NULL;
m_pICommandText = NULL;
TableID.uName.pwszName = NULL;
m_pIDataInitialize = NULL;
SetColType();
SetColLen();
} CNativeClientOLEDB::~CNativeClientOLEDB(void)
{
ReleaseSessionAndCommand();
UnInit();
} HRESULT CNativeClientOLEDB::Init(CStringW strDataSource, CStringW strUserID, CStringW strPassWD, CStringW strCataLOG)
{
HRESULT hr = NOERROR;
// One property set for initializing.
DBPROPSET rgPropertySets[];
// Properties within above property set.
DBPROP rgDBProperties[g_cOPTION];
do
{
// Basic initialization.
if (FAILED(CoInitialize(NULL)))
break;
else
m_bInitialized = TRUE; hr = CoGetMalloc(MEMCTX_TASK, &m_pIMalloc);
if ((!m_pIMalloc) || FAILED(hr))
break; // Set up property set for call to IDBInitialize in CreateSessionCommand.
rgPropertySets[].rgProperties = rgDBProperties;
rgPropertySets[].cProperties = g_cOPTION;
rgPropertySets[].guidPropertySet = DBPROPSET_DBINIT; SetupOption(DBPROP_INIT_DATASOURCE, (WCHAR *)(LPCWSTR)strDataSource, &rgDBProperties[]);
SetupOption(DBPROP_INIT_CATALOG, (WCHAR *)(LPCWSTR)strCataLOG, &rgDBProperties[]);
SetupOption(DBPROP_AUTH_USERID, (WCHAR *)(LPCWSTR)strUserID, &rgDBProperties[]);
SetupOption(DBPROP_AUTH_PASSWORD, (WCHAR *)(LPCWSTR)strPassWD, &rgDBProperties[]); //if (S_OK != (hr = DBInitAndConnect(rgPropertySets, 1, SQLNCLI_CLSID)))
if (S_OK != (hr = DBInitAndConnect(rgPropertySets, , CLSID_SQLNCLI11)))
break;
return S_OK;
} while (); return hr;
} HRESULT CNativeClientOLEDB::Init(CStringW strConnectionString)
{
HRESULT hr = S_OK;
do
{ if (FAILED(CoInitialize(NULL)))
break;
else
m_bInitialized = TRUE; hr = CoCreateInstance(
CLSID_MSDAINITIALIZE,
NULL,
CLSCTX_INPROC_SERVER,
IID_IDataInitialize,
reinterpret_cast<LPVOID *>(&m_pIDataInitialize));
if (!SUCCEEDED(hr))
break; hr = m_pIDataInitialize->GetDataSource(
NULL,
CLSCTX_INPROC_SERVER,
strConnectionString,
IID_IDBInitialize,
reinterpret_cast<IUnknown **>(&m_pIDBInitialize)); if (!SUCCEEDED(hr))
break; if (!SUCCEEDED(hr = m_pIDBInitialize->Initialize())) {
printf("Call to initialize failed.\n");
break;
} return S_OK; } while (); UnInit();
return hr;
} void CNativeClientOLEDB::UnInit()
{
HRESULT hr = NOERROR; //ReleaseSessionAndCommand();
//ReleaseSessionIOpenRowset(); if (m_pIMalloc){
m_pIMalloc->Release();
m_pIMalloc = NULL;
} if (m_pIDBInitialize) {
hr = m_pIDBInitialize->Uninitialize();
m_pIDBInitialize = NULL;
if (FAILED(hr))
printf("Uninitialize failed\n");
} if (m_bInitialized){
CoUninitialize();
m_bInitialized = FALSE;
} if (SUCCEEDED(hr))
printf("Test completed successfully.\n\n");
else
printf("Test failed.\n\n"); } void CNativeClientOLEDB::SetColType(void)
{ } void CNativeClientOLEDB::SetColLen(void)
{ } void CNativeClientOLEDB::set_bindings()
{ } void CNativeClientOLEDB::set_bind(DBBINDING &binding, int col, DBBYTEOFFSET len_offset, DBBYTEOFFSET status_offset, DBBYTEOFFSET value_offset, DBLENGTH len, DBTYPE type)
{
binding.dwPart = DBPART_VALUE | DBPART_LENGTH | DBPART_STATUS;
binding.iOrdinal = col;
binding.pTypeInfo = NULL;
binding.obValue = value_offset;
binding.obLength = len_offset;
binding.obStatus = status_offset;
binding.cbMaxLen = len; // Size of varchar column.
binding.pTypeInfo = NULL;
binding.pObject = NULL;
binding.pBindExt = NULL;
binding.dwFlags = ;
binding.eParamIO = DBPARAMIO_NOTPARAM;
binding.dwMemOwner = DBMEMOWNER_CLIENTOWNED;
binding.bPrecision = ;
binding.bScale = ;
binding.wType = type;
} HRESULT CNativeClientOLEDB::DBInitAndConnect(DBPROPSET* rgPropertySets, ULONG ulcPropCount, CLSID clsidProv)
{
HRESULT hr = NOERROR;
IDBProperties* pIDBProperties = NULL;
UWORD i = , j = ; // indexes. if (ulcPropCount && !rgPropertySets) {
hr = E_INVALIDARG;
return hr;
} if (S_OK != (hr = CoCreateInstance(clsidProv,
NULL, CLSCTX_INPROC_SERVER,
IID_IDBInitialize,
(void **)&m_pIDBInitialize))){
goto CLEANUP;
} if (S_OK != (hr = m_pIDBInitialize->QueryInterface(IID_IDBProperties,
(void **)&pIDBProperties)))
goto CLEANUP; if (S_OK != (hr = pIDBProperties->SetProperties(ulcPropCount, rgPropertySets))){
goto CLEANUP;
} if (S_OK != (hr = m_pIDBInitialize->Initialize())) { printf("Call to initialize failed.\n");
goto CLEANUP;
} CLEANUP:
if (pIDBProperties)
pIDBProperties->Release(); for (i = ; i < ulcPropCount; i++)
for (j = ; j < rgPropertySets[i].cProperties; j++)
VariantClear(&(rgPropertySets[i].rgProperties[j]).vValue);
return hr;
} void CNativeClientOLEDB::DumpErrorInfo(IUnknown* pObjectWithError, REFIID IID_InterfaceWithError)
{
// Interfaces used in the example.
IErrorInfo* pIErrorInfoAll = NULL;
IErrorInfo* pIErrorInfoRecord = NULL;
IErrorRecords* pIErrorRecords = NULL;
ISupportErrorInfo* pISupportErrorInfo = NULL;
ISQLErrorInfo* pISQLErrorInfo = NULL;
ISQLServerErrorInfo* pISQLServerErrorInfo = NULL; // Number of error records.
ULONG nRecs;
ULONG nRec; // Basic error information from GetBasicErrorInfo.
ERRORINFO errorinfo; // IErrorInfo values.
BSTR bstrDescription;
BSTR bstrSource; // ISQLErrorInfo parameters.
BSTR bstrSQLSTATE;
LONG lNativeError; // ISQLServerErrorInfo parameter pointers.
SSERRORINFO* pSSErrorInfo = NULL;
OLECHAR* pSSErrorStrings = NULL; // Hard-code an American English locale for the example.
DWORD MYLOCALEID = 0x0409; // Only ask for error information if the interface supports
// it.
if (FAILED(pObjectWithError->QueryInterface(IID_ISupportErrorInfo,
(void**)&pISupportErrorInfo)))
{
wprintf_s(L"SupportErrorErrorInfo interface not supported");
return;
}
if (FAILED(pISupportErrorInfo->
InterfaceSupportsErrorInfo(IID_InterfaceWithError)))
{
wprintf_s(L"InterfaceWithError interface not supported");
return;
} // Do not test the return of GetErrorInfo. It can succeed and return
// a NULL pointer in pIErrorInfoAll. Simply test the pointer.
GetErrorInfo(, &pIErrorInfoAll); if (pIErrorInfoAll != NULL)
{
// Test to see if it's a valid OLE DB IErrorInfo interface
// exposing a list of records.
if (SUCCEEDED(pIErrorInfoAll->QueryInterface(IID_IErrorRecords,
(void**)&pIErrorRecords)))
{
pIErrorRecords->GetRecordCount(&nRecs); // Within each record, retrieve information from each
// of the defined interfaces.
for (nRec = ; nRec < nRecs; nRec++)
{
// From IErrorRecords, get the HRESULT and a reference
// to the ISQLErrorInfo interface.
pIErrorRecords->GetBasicErrorInfo(nRec, &errorinfo);
pIErrorRecords->GetCustomErrorObject(nRec,
IID_ISQLErrorInfo, (IUnknown**)&pISQLErrorInfo); // Display the HRESULT, then use the ISQLErrorInfo.
wprintf_s(L"HRESULT:\t%#X\n", errorinfo.hrError); if (pISQLErrorInfo != NULL)
{
pISQLErrorInfo->GetSQLInfo(&bstrSQLSTATE,
&lNativeError); // Display the SQLSTATE and native error values.
wprintf_s(L"SQLSTATE:\t%s\nNative Error:\t%ld\n",
bstrSQLSTATE, lNativeError); // SysFree BSTR references.
SysFreeString(bstrSQLSTATE); // Get the ISQLServerErrorInfo interface from
// ISQLErrorInfo before releasing the reference.
pISQLErrorInfo->QueryInterface(
IID_ISQLServerErrorInfo,
(void**)&pISQLServerErrorInfo); pISQLErrorInfo->Release();
} // Test to ensure the reference is valid, then
// get error information from ISQLServerErrorInfo.
if (pISQLServerErrorInfo != NULL)
{
pISQLServerErrorInfo->GetErrorInfo(&pSSErrorInfo,
&pSSErrorStrings); // ISQLServerErrorInfo::GetErrorInfo succeeds
// even when it has nothing to return. Test the
// pointers before using.
if (pSSErrorInfo)
{
// Display the state and severity from the
// returned information. The error message comes
// from IErrorInfo::GetDescription.
wprintf_s(L"Error state:\t%d\nSeverity:\t%d\n",
pSSErrorInfo->bState,
pSSErrorInfo->bClass); // IMalloc::Free needed to release references
// on returned values. For the example, assume
// the g_pIMalloc pointer is valid.
m_pIMalloc->Free(pSSErrorStrings);
m_pIMalloc->Free(pSSErrorInfo);
} pISQLServerErrorInfo->Release();
} if (SUCCEEDED(pIErrorRecords->GetErrorInfo(nRec,
MYLOCALEID, &pIErrorInfoRecord)))
{
// Get the source and description (error message)
// from the record's IErrorInfo.
pIErrorInfoRecord->GetSource(&bstrSource);
pIErrorInfoRecord->GetDescription(&bstrDescription); if (bstrSource != NULL)
{
wprintf_s(L"Source:\t\t%s\n", bstrSource);
SysFreeString(bstrSource);
}
if (bstrDescription != NULL)
{
wprintf_s(L"Error message:\t%s\n",
bstrDescription);
SysFreeString(bstrDescription);
} pIErrorInfoRecord->Release();
}
} pIErrorRecords->Release();
}
else
{
// IErrorInfo is valid; get the source and
// description to see what it is.
pIErrorInfoAll->GetSource(&bstrSource);
pIErrorInfoAll->GetDescription(&bstrDescription); if (bstrSource != NULL)
{
wprintf_s(L"Source:\t\t%s\n", bstrSource);
SysFreeString(bstrSource);
}
if (bstrDescription != NULL)
{
wprintf_s(L"Error message:\t%s\n", bstrDescription);
SysFreeString(bstrDescription);
}
} pIErrorInfoAll->Release();
}
else
{
wprintf_s(L"GetErrorInfo failed.");
} pISupportErrorInfo->Release(); return;
} void CNativeClientOLEDB::SetupOption(DBPROPID PropID, WCHAR *wszVal, DBPROP * pDBProp)
{
pDBProp->dwPropertyID = PropID;
pDBProp->dwOptions = DBPROPOPTIONS_REQUIRED;
pDBProp->colid = DB_NULLID;
pDBProp->vValue.vt = VT_BSTR;
pDBProp->vValue.bstrVal = SysAllocStringLen(wszVal, wcslen(wszVal));
} HRESULT CNativeClientOLEDB::SetFastLoadProperty(BOOL fSet)
{
HRESULT hr = S_OK;
IDBProperties* pIDBProps = NULL;
DBPROP rgProps[];
DBPROPSET PropSet; VariantInit(&rgProps[].vValue); rgProps[].dwOptions = DBPROPOPTIONS_REQUIRED;
rgProps[].colid = DB_NULLID;
rgProps[].vValue.vt = VT_BOOL;
rgProps[].dwPropertyID = SSPROP_ENABLEFASTLOAD; if (fSet == TRUE)
rgProps[].vValue.boolVal = VARIANT_TRUE;
else
rgProps[].vValue.boolVal = VARIANT_FALSE; PropSet.rgProperties = rgProps;
PropSet.cProperties = ;
PropSet.guidPropertySet = DBPROPSET_SQLSERVERDATASOURCE; if (SUCCEEDED(hr = m_pIDBInitialize->QueryInterface(IID_IDBProperties, (LPVOID *)&pIDBProps)))
hr = pIDBProps->SetProperties(, &PropSet); VariantClear(&rgProps[].vValue); if (pIDBProps)
pIDBProps->Release(); return hr;
} HRESULT CNativeClientOLEDB::FastQueryData(CStringW strSql,ULONG& nColNum,IRowset** pIRowset,IAccessor** pIAccessor, HACCESSOR& hAccessor)
{ HRESULT hr = E_FAIL;
if (NULL != *pIRowset || NULL != *pIAccessor || strSql.IsEmpty() || NULL == m_pICommandText || NULL == m_pICommand || nColNum <= ){
return hr;
}
do
{
if (FAILED(hr = m_pICommandText->SetCommandText(DBGUID_DBSQL, strSql))){
break;
} LONG lAffected;
if (FAILED(hr = m_pICommand->Execute(NULL, IID_IRowset, NULL, &lAffected, (IUnknown **)pIRowset))){
break;
} if (FAILED(hr = (*pIRowset)->QueryInterface(IID_IAccessor, (void **)pIAccessor))){
break;
} set_bindings(); DBBINDSTATUS dbs[_MAX_COL_NUM] = { };
if (FAILED(hr = (*pIAccessor)->CreateAccessor(DBACCESSOR_ROWDATA, (DBCOUNTITEM)nColNum, m_bindings, sizeof(Data),&hAccessor, dbs))){
//dbs是绑定状态
break;
} return S_OK;
} while (); ReleaseRowsetAndIAccessor(pIRowset, pIAccessor, hAccessor);
} HRESULT CNativeClientOLEDB::FastInsertData(CStringW strTable, ULONG& nColNum, IRowsetFastLoad** pIRowsetFastLoad, IAccessor** pIAccessor, HACCESSOR& hAccessor)
{
HRESULT hr = E_FAIL;
TableID.uName.pwszName = NULL;
TableID.eKind = DBKIND_NAME;
TableID.uName.pwszName = new WCHAR[strTable.GetLength() + ];
wcsncpy_s(TableID.uName.pwszName, strTable.GetLength() + , strTable, strTable.GetLength() + );
TableID.uName.pwszName[strTable.GetLength() + ] = (WCHAR)NULL; do
{
// Get IRowsetFastLoad initialized to use the test table.
if (FAILED(hr = m_pIOpenRowset->OpenRowset(NULL, &TableID, NULL, IID_IRowsetFastLoad, , NULL, (LPUNKNOWN *)pIRowsetFastLoad))){
break;
} set_bindings();
DBBINDSTATUS bds[_MAX_COL_NUM] = { };
if (FAILED(hr = (*pIRowsetFastLoad)->QueryInterface(IID_IAccessor, (void **)pIAccessor))){
break;
} if (FAILED(hr = (*pIAccessor)->CreateAccessor(DBACCESSOR_ROWDATA, (DBCOUNTITEM)nColNum, m_bindings, (ROUND_UP(sizeof(Data), COLUMN_ALIGNVAL)), &hAccessor, bds))){
//dbs是绑定状态
break;
} return S_OK;
} while (); ReleaseRowsetFastLoadAndIAccessor(pIRowsetFastLoad, pIAccessor, hAccessor);
return E_FAIL;
} HRESULT CNativeClientOLEDB::ReleaseRowsetAndIAccessor(IRowset** pIRowset,IAccessor** pIAccessor,const HACCESSOR& hAccessor)
{
HRESULT hr = S_OK;
if (*pIRowset){
(*pIRowset)->Release();
(*pIRowset) = NULL;
} if (*pIAccessor && hAccessor){
if (FAILED((*pIAccessor)->ReleaseAccessor(hAccessor, NULL))){
hr = E_FAIL;
}
(*pIAccessor)->Release();
*pIAccessor = NULL;
} return hr;
} HRESULT CNativeClientOLEDB::ReleaseRowsetFastLoadAndIAccessor(IRowsetFastLoad** pIRowset,IAccessor** pIAccessor,const HACCESSOR& hAccessor)
{ HRESULT hr = S_OK;
if (FAILED(hr = SetFastLoadProperty(FALSE)))
printf("SetFastLoadProperty(FALSE) failed with %x", hr); if (*pIAccessor && hAccessor)
if (FAILED((*pIAccessor)->ReleaseAccessor(hAccessor, NULL)))
hr = E_FAIL; if (*pIAccessor){
(*pIAccessor)->Release();
*pIAccessor = NULL;
} if (*pIRowset){
(*pIRowset)->Release();
(*pIRowset) = NULL;
} if (TableID.uName.pwszName)
delete[]TableID.uName.pwszName; return hr;
} HRESULT CNativeClientOLEDB::CreateSessionAndCommand()
{
HRESULT hr = E_FAIL;
if (NULL == m_pIDBInitialize || m_pIDBSession || m_pIOpenRowset || m_pIDBCreateCommand || m_pICommand || m_pICommandText){
return hr;
} do
{
if (FAILED(hr =
m_pIDBInitialize->QueryInterface(IID_IDBCreateSession, (void **)&m_pIDBSession)))
break; if (FAILED(hr =
m_pIDBSession->CreateSession(NULL, IID_IOpenRowset, (IUnknown **)&m_pIOpenRowset )))
break; if (FAILED(hr = m_pIOpenRowset ->QueryInterface(IID_IDBCreateCommand, (void **)&m_pIDBCreateCommand))){
break;
} if (FAILED(hr = m_pIDBCreateCommand->CreateCommand(NULL, IID_ICommand, (IUnknown **)&m_pICommand))){
break;
} if (FAILED(hr = m_pICommand->QueryInterface(&m_pICommandText))){
break;
} return S_OK; } while (); ReleaseSessionAndCommand();
return hr;
} HRESULT CNativeClientOLEDB::ReleaseSessionAndCommand()
{
HRESULT hr = S_OK;
if (m_pICommandText){
m_pICommandText->Release();
m_pICommandText = NULL;
} if (m_pICommand){
m_pICommand->Release();
m_pICommand = NULL;
} if (m_pIDBCreateCommand){
m_pIDBCreateCommand->Release();
m_pIDBCreateCommand = NULL;
} if (m_pIOpenRowset){
m_pIOpenRowset->Release();
m_pIOpenRowset = NULL;
} if (m_pIDBSession){
m_pIDBSession->Release();
m_pIDBSession = NULL;
} return S_OK;
} HRESULT CNativeClientOLEDB::SetPropertiesAndCreateSessionAndIOpenRowset(BOOL bFast /*= TRUE*/)
{
HRESULT hr;
if (NULL == m_pIDBInitialize){
return E_FAIL;
}
do
{
if (FAILED(hr = SetFastLoadProperty(bFast)))
break; if (FAILED(hr =
m_pIDBInitialize->QueryInterface(IID_IDBCreateSession, (void **)&m_pIDBSession)))
break; if (FAILED(hr =
m_pIDBSession->CreateSession(NULL, IID_IOpenRowset, (IUnknown **)&m_pIOpenRowset)))
break; return S_OK;
} while ();
// Get the fastload pointer. ReleaseSessionIOpenRowset();
return E_FAIL;
} HRESULT CNativeClientOLEDB::ReleaseSessionIOpenRowset()
{
if (m_pIDBSession){
m_pIDBSession->Release();
m_pIDBSession = NULL;
} if (m_pIOpenRowset){
m_pIOpenRowset->Release();
m_pIOpenRowset = NULL;
}
return S_OK;
}
以上两个文件,基本覆盖了创建\连接\释放等等的过程.下面对某些函数进行讲解一下;
1. 调用CoInitialize 来初始化控件.因为它是基于com组件的.
2. 通过调用 CoCreateInstance 方法来创建数据源对象的实例。
每个 OLE DB 访问接口都具有一个唯一的类标识符 (CLSID)。 对于 SQL Server Native Client OLE DB 访问接口,类标识符为 CLSID_SQLNCLI10。 也可以使用符号 SQLNCLI_CLSID,该符号将解析为您引用的 sqlncli.h 中使用的 SQL Server Native Client OLE DB 访问接口。
数据源对象公开了 IDBProperties 接口,使用者使用该接口提供基本的身份验证信息,如服务器名、数据库名、用户 ID 和密码。 可调用IDBProperties::SetProperties 方法设置这些属性。
3. 调用 IDBProperties::Initialize 接口来建立与数据源的连接.
4. 在建立与某一数据源的连接后,使用者调用 IDBCreateSession::CreateSession 方法以创建一个会话。 该会话充当命令、行集或事务工厂。
5. IOpenRowset::OpenRowset 方法打开并返回一个行集,该行集包括来自单个基表或索引的所有行。
6. 执行IDBCreateCommand::CreateCommand 方法,以便为 ICommandText 接口创建一个命令对象和请求。
7. 利用 ICommandText::SetCommandText 指定要执行的命令。
当然在我的代码中有 set_bindings(); 这个函数是用来把数据库中的类型与OLEDB中的数据类型进行一个绑定. 可以参照:
https://msdn.microsoft.com/zh-cn/library/ms130984.aspx
8. 调用 Execute 命令用于执行该命令。
9. 从IRowset中取出数据等等操作.
10. 调用ReleaseRowsetAndIAccessor 来释放RowSet和IAccessor
11. 调用 ReleaseSessionAndCommand 来释放会话和命令
12. 最后调用UnInit 来释放连接.
上面是基于底层封装的数据源操作部分.下面给出与数据相关的操作的类.
//HistoryDataOLEDB.h
#pragma once
#include <OLEDB/NativeClientOLEDB.h> #pragma pack(push, 1)
class HistoryData :
public Data{
public:
/*
SDWORD SOID_len; // Length of data (not space allocated).
DWORD SOID_status; // Status of column.
int SOID_value; SDWORD TerminalID_len; // Length of data (not space allocated).
DWORD TerminalID_status; // Status of column.
int TerminalID_value;
*/
SDWORD Longitude_len; // Length of data (not space allocated).
DWORD Longitude_status; // Status of column.
int Longitude_value; SDWORD Latitude_len; // Length of data (not space allocated).
DWORD Latitude_status; // Status of column.
int Latitude_value; SDWORD Speed_len; // Length of data (not space allocated).
DWORD Speed_status; // Status of column.
WORD Speed_value; // SDWORD Direction_len; // Length of data (not space allocated).
DWORD Direction_status; // Status of column.
WORD Direction_value; SDWORD Height_len; // Length of data (not space allocated).
DWORD Height_status; // Status of column.
short Height_value; SDWORD Lock_len; // Length of data (not space allocated).
DWORD Lock_status; // Status of column.
BYTE Lock_value; SDWORD Gpstime_len; // Length of data (not space allocated).
DWORD Gpstime_status; // Status of column.
char Gpstime_value[]; SDWORD InStatus_len; // Length of data (not space allocated).
DWORD InStatus_status; // Status of column.
short InStatus_value; //
SDWORD TmlStatus_len; // Length of data (not space allocated).
DWORD TmlStatus_status; // Status of column.
short TmlStatus_value; SDWORD WarnFlag_len; // Length of data (not space allocated).
DWORD WarnFlag_status; // Status of column.
short WarnFlag_value; SDWORD Resver2_len; // Length of data (not space allocated).
DWORD Resver2_status; // Status of column.
short Resver2_value; SDWORD Alldis_len; // Length of data (not space allocated).
DWORD Alldis_status; // Status of column.
int Alldis_value; SDWORD Temperature_len; // Length of data (not space allocated).
DWORD Temperature_status; // Status of column.
int Temperature_value; //
SDWORD Oil_len; // Length of data (not space allocated).
DWORD Oil_status; // Status of column.
short Oil_value; SDWORD Smsid1_len; // Length of data (not space allocated).
DWORD Smaid1_status; // Status of column.
short Smaid1_value; SDWORD Smaid2_len; // Length of data (not space allocated).
DWORD Smaid2_status; // Status of column.
short Smaid2_value;
/*
SDWORD Longitude2_len; // Length of data (not space allocated).
DWORD Longitude2_status; // Status of column.
int Longitude2_value; SDWORD Latitude2_len; // Length of data (not space allocated).
DWORD Latitude2_status; // Status of column.
int Latitude2_value;
*/
//
SDWORD AffixData_len; // Length of data (not space allocated).
DWORD AffixData_status; // Status of column.
char AffixData_value[];
};
#pragma pack(pop) class CHistoryDataOLEDB :
public CNativeClientOLEDB
{
public:
CHistoryDataOLEDB(void);
~CHistoryDataOLEDB(void); virtual void SetColType(void); virtual void SetColLen(void); virtual void set_bindings(); void Lock() { cs.Lock(); };
void Unlock() { cs.Unlock(); }; public:
//快速查询数据
LPBYTE FastQueryData(CStringW strSql,ULONG nColNum, int* nLen, int* nCount);
//快速插入数据
BOOL FastInsertData(const CStringW strTable, HistoryData* const pData, const int nDataNum); private:
CCriticalSection cs;
};
//HistoryDataOLEDB.cpp
#include "StdAfx.h"
#include "HistoryDataOLEDB.h"
#include "HistoryDefine.h"
#include "Base64.h" CHistoryDataOLEDB::CHistoryDataOLEDB(void)
{
SetColLen();
SetColType();
} CHistoryDataOLEDB::~CHistoryDataOLEDB(void)
{
} void CHistoryDataOLEDB::SetColType(void)
{
col_type[] = DBTYPE_I4;
col_type[] = DBTYPE_I4;
col_type[] = DBTYPE_I4;
col_type[] = DBTYPE_I4;
col_type[] = DBTYPE_I2; col_type[] = DBTYPE_I2;
col_type[] = DBTYPE_I2;
col_type[] = DBTYPE_UI1;
col_type[] = DBTYPE_STR;
col_type[] = DBTYPE_I2; col_type[] = DBTYPE_I2;
col_type[] = DBTYPE_I2;
col_type[] = DBTYPE_I2;
col_type[] = DBTYPE_I4;
col_type[] = DBTYPE_I4; col_type[] = DBTYPE_I2;
col_type[] = DBTYPE_I2;
col_type[] = DBTYPE_I2;
col_type[] = DBTYPE_I4;
col_type[] = DBTYPE_I4; col_type[] = DBTYPE_STR;
} void CHistoryDataOLEDB::SetColLen(void)
{
col_len[] = sizeof(int);
col_len[] = sizeof(int);
col_len[] = sizeof(int);
col_len[] = sizeof(int);
col_len[] = sizeof(short); col_len[] = sizeof(short);
col_len[] = sizeof(short);
col_len[] = sizeof(char);
col_len[] = ;
col_len[] = sizeof(short); col_len[] = sizeof(short);
col_len[] = sizeof(short);
col_len[] = sizeof(short);
col_len[] = sizeof(int);
col_len[] = sizeof(int); col_len[] = sizeof(short);
col_len[] = sizeof(short);
col_len[] = sizeof(short);
col_len[] = sizeof(int);
col_len[] = sizeof(int); col_len[] = ;
} void CHistoryDataOLEDB::set_bindings()
{
set_bind(m_bindings[], , offsetof(HistoryData, Longitude_len), offsetof(HistoryData, Longitude_status), offsetof(HistoryData, Longitude_value), col_len[], col_type[]);
set_bind(m_bindings[], , offsetof(HistoryData, Latitude_len), offsetof(HistoryData, Latitude_status), offsetof(HistoryData, Latitude_value), col_len[], col_type[]);
set_bind(m_bindings[], , offsetof(HistoryData, Speed_len), offsetof(HistoryData, Speed_status), offsetof(HistoryData, Speed_value), col_len[], col_type[]); set_bind(m_bindings[], , offsetof(HistoryData, Direction_len), offsetof(HistoryData, Direction_status), offsetof(HistoryData, Direction_value), col_len[], col_type[]);
set_bind(m_bindings[], , offsetof(HistoryData, Height_len), offsetof(HistoryData, Height_status), offsetof(HistoryData, Height_value), col_len[], col_type[]);
set_bind(m_bindings[], , offsetof(HistoryData, Lock_len), offsetof(HistoryData, Lock_status), offsetof(HistoryData, Lock_value), col_len[], col_type[]);
set_bind(m_bindings[], , offsetof(HistoryData, Gpstime_len), offsetof(HistoryData, Gpstime_status), offsetof(HistoryData, Gpstime_value), col_len[], col_type[]);
set_bind(m_bindings[], , offsetof(HistoryData, InStatus_len), offsetof(HistoryData, InStatus_status), offsetof(HistoryData, InStatus_value), col_len[], col_type[]); set_bind(m_bindings[], , offsetof(HistoryData, TmlStatus_len), offsetof(HistoryData, TmlStatus_status), offsetof(HistoryData, TmlStatus_value), col_len[], col_type[]);
set_bind(m_bindings[], , offsetof(HistoryData, WarnFlag_len), offsetof(HistoryData, WarnFlag_status), offsetof(HistoryData, WarnFlag_value), col_len[], col_type[]);
set_bind(m_bindings[], , offsetof(HistoryData, Resver2_len), offsetof(HistoryData, Resver2_status), offsetof(HistoryData, Resver2_value), col_len[], col_type[]);
set_bind(m_bindings[], , offsetof(HistoryData, Alldis_len), offsetof(HistoryData, Alldis_status), offsetof(HistoryData, Alldis_value), col_len[], col_type[]);
set_bind(m_bindings[], , offsetof(HistoryData, Temperature_len), offsetof(HistoryData, Temperature_status), offsetof(HistoryData, Temperature_value), col_len[], col_type[]); set_bind(m_bindings[], , offsetof(HistoryData, Oil_len), offsetof(HistoryData, Oil_status), offsetof(HistoryData, Oil_value), col_len[], col_type[]);
set_bind(m_bindings[], , offsetof(HistoryData, Smsid1_len), offsetof(HistoryData, Smaid1_status), offsetof(HistoryData, Smaid1_value), col_len[], col_type[]);
set_bind(m_bindings[], , offsetof(HistoryData, Smaid2_len), offsetof(HistoryData, Smaid2_status), offsetof(HistoryData, Smaid2_value), col_len[], col_type[]); set_bind(m_bindings[], , offsetof(HistoryData, AffixData_len), offsetof(HistoryData, AffixData_status), offsetof(HistoryData, AffixData_value), col_len[], col_type[]); } LPBYTE CHistoryDataOLEDB::FastQueryData(CStringW strSql,ULONG nColNum, int* nLen, int* nCount)
{
HRESULT hr = E_FAIL;
HistoryData rmd; //历史数据
HROW* rghRows = NULL;
LONG cRows = ; //一次读取10行
ULONG uRowsObtained = ; //实际读取的条数 IRowset *pIRowset = NULL;
IAccessor* pIAccessor = NULL;
HACCESSOR hAccessor = DB_NULL_HACCESSOR;
if (S_OK != (hr = CNativeClientOLEDB::FastQueryData(strSql, nColNum, &pIRowset, &pIAccessor, hAccessor))){
return NULL;
}
LPBYTE lpData = new BYTE[ * * ];
ZeroMemory(lpData, * * );
int nDataLen = ;
int nDataCount = ;
while (FALSE == FAILED(hr = pIRowset->GetNextRows( DB_NULL_HCHAPTER, , cRows, &uRowsObtained, &rghRows)))
{
int j = ;
if (cRows != uRowsObtained){
printf("cRows != uRowsObtained.\n");
} for (int i = ; i < uRowsObtained; ++i){
if (FAILED( hr = pIRowset->GetData(rghRows[i], hAccessor, &rmd )))
{
printf("获取数据失败 %d .\r\n", i);
break;
//std::cout << "获取数据失败." << std::endl;
} if (rmd.AffixData_status != || rmd.Alldis_status != || rmd.Direction_status != || rmd.Gpstime_status != ||
rmd.Height_status != || rmd.InStatus_status != || rmd.Latitude_status != || rmd.Latitude_status != || rmd.Lock_status != ||
rmd.Oil_status != || rmd.Speed_status != || rmd.Direction_status != ||
rmd.Resver2_status != || rmd.Smaid1_status != || rmd.Smaid2_status != || rmd.Temperature_status != ||
rmd.WarnFlag_status != ){
ASSERT();
break;
} HistoryGPSData gpsdata;
memset(&gpsdata, , sizeof(HistoryGPSData));
gpsdata.longitude = rmd.Longitude_value;
gpsdata.latitude = rmd.Latitude_value;
gpsdata.speed = rmd.Speed_value;
gpsdata.direction = rmd.Direction_value;
gpsdata.gpsHeight = rmd.Height_value;
gpsdata.byLock = rmd.Lock_value;
//TRACE("%s\n", rmd.Gpstime_value);
SYSTEMTIME sysGps;
sscanf(rmd.Gpstime_value, "%d-%d-%d %d:%d:%d", &sysGps.wYear, &sysGps.wMonth, &sysGps.wDay, &sysGps.wHour, &sysGps.wMinute, &sysGps.wSecond);
gpsdata.gpstm[] = sysGps.wYear - ;
gpsdata.gpstm[] = sysGps.wMonth;
gpsdata.gpstm[] = sysGps.wDay;
gpsdata.gpstm[] = sysGps.wHour;
gpsdata.gpstm[] = sysGps.wMinute;
gpsdata.gpstm[] = sysGps.wSecond;
int nInStatus = rmd.InStatus_value;
gpsdata.InStatus1 = nInStatus & 0xFF;
gpsdata.InStatus2 = (nInStatus >> ) & 0xFF;
int nTmlStatus = rmd.TmlStatus_value;
gpsdata.TmlStatus1 = nTmlStatus & 0xFF;
gpsdata.TmlStatus2 = (nTmlStatus >> ) & 0xFF;
int nWarnFlag = rmd.WarnFlag_value;
gpsdata.WarnFlag1 = nWarnFlag & 0xFF;
gpsdata.WarnFlag2 = (nWarnFlag >> ) & 0xFF;
int resver2 = rmd.Resver2_value;
gpsdata.extflag = resver2 &0xFF;
gpsdata.netid = (resver2 >> ) & 0xFF;
gpsdata.alldis = rmd.Alldis_value;
int nTemperatue = rmd.Temperature_value;
memcpy(gpsdata.temperture, &nTemperatue, );
gpsdata.oil = rmd.Oil_value;
gpsdata.cellid = rmd.Smaid2_value;
gpsdata.lacid = rmd.Smaid1_value;
CString strAffixData = rmd.AffixData_value; gpsdata.longitude = htonl(gpsdata.longitude);
gpsdata.latitude = htonl(gpsdata.latitude);
gpsdata.speed = htons(gpsdata.speed);
gpsdata.direction = htons(gpsdata.direction);
gpsdata.gpsHeight = htons(gpsdata.gpsHeight);
gpsdata.alldis = htonl(gpsdata.alldis);
gpsdata.oil = htons(gpsdata.oil);
gpsdata.cellid = htons(gpsdata.cellid);
gpsdata.lacid = htons(gpsdata.lacid); nDataCount++;
memcpy(lpData + nDataLen, &gpsdata, sizeof(HistoryGPSData));
nDataLen += sizeof(HistoryGPSData); //写入扩展数据
if(!strAffixData.IsEmpty())
{
BYTE bAffixData[] = {};
int nSrcLen = strAffixData.GetLength();
LPBYTE pSrcData = (LPBYTE)strAffixData.GetBuffer();
int nAffixLen = base64_decode(bAffixData, pSrcData, nSrcLen);
strAffixData.ReleaseBuffer();
if(nAffixLen > )
{
int nTmpLen = nAffixLen - ;
bAffixData[] = (nTmpLen >> ) & 0xFF;
bAffixData[] = nTmpLen & 0xFF;
memcpy(lpData + nDataLen, bAffixData, nAffixLen);
nDataLen += nAffixLen;
}
}
} if (uRowsObtained){
pIRowset->ReleaseRows(uRowsObtained, rghRows, NULL, NULL, NULL);
}
//释放
CoTaskMemFree(rghRows);
rghRows = NULL; if (hr == DB_S_ENDOFROWSET){
printf("数据已经全部读取完成共计:%d 条.", nDataCount);
break;
}
} //释放 IRowSet 和 IAccessor
ReleaseRowsetAndIAccessor(&pIRowset, &pIAccessor, hAccessor); if ( == nDataLen){
delete[] lpData;
lpData = NULL;
nDataCount = ;
nDataLen = ;
}
*nLen = nDataLen;
*nCount = nDataCount;
return lpData;
} BOOL CHistoryDataOLEDB::FastInsertData(const CStringW strTable, HistoryData* const pData, const int nDataNum)
{
if (NULL == pData || == nDataNum || strTable.IsEmpty()){
return TRUE;
} HRESULT hr = NOERROR;
IRowsetFastLoad * pIRowsetFastLoad = NULL;
IAccessor* pIAccessor = NULL;
HACCESSOR hAccessor = ;
ULONG nColNum = ;
if (S_OK != (hr = CNativeClientOLEDB::FastInsertData(strTable, nColNum, &pIRowsetFastLoad, &pIAccessor, hAccessor))){
return FALSE;
}
BOOL bRet = TRUE;
for (int i = ; i < nDataNum; i++){
if (FAILED(hr = pIRowsetFastLoad->InsertRow(hAccessor, &pData[i])))
{ DumpErrorInfo(pIRowsetFastLoad, IID_ISQLServerErrorInfo);
bRet = TRUE;
break;
}
}
//全部插入之后,提交一次
if (FAILED(hr = pIRowsetFastLoad->Commit(TRUE)))
{
DumpErrorInfo(pIRowsetFastLoad, IID_ISQLServerErrorInfo);
bRet = TRUE;
printf("Error on IRFL::Commit\n");
} ReleaseRowsetFastLoadAndIAccessor(&pIRowsetFastLoad, &pIAccessor, hAccessor);
if (bRet){
return FALSE;
} else {
return TRUE;
}
}
这个类继承于前面的类,用于对历史数据表的读取与插入. 以下我简单地说明一下:
1. 重写SetColLen() 来设置每列数据的长度.用于绑定
2. 重写SetColType() 来设置每列数据的类别.用于绑定
3. 重写 set_bindings() 来进行绑定.
4. FastQueryData 函数是快速查询数据的接口.
调用父类的FastQueryData来取得数据.利用GetNextRows从IRowset中取得数据.
5. 释放 IRowSet 和 IAccessor
6. 数据都是以数据流的方式查询返回和插入.
到此为止,基本OLEDB 操作算是结束了.
后续. 我写了个数据池来存储数据源的多个连接.其中也利用了信号量来保证了多线程同步的问题.
//CNativeClientOLEDBPool.h
#pragma once #include <list>
using namespace std; template <class T>
class CNativeClientOLEDBPool
{
public:
CNativeClientOLEDBPool(void){
m_hSemaphore = NULL;
m_nMaxCount = ;
}
~CNativeClientOLEDBPool(void){
Clear();
}
//static CNativeClientOLEDBPool* Instance() { return &m_Instance; } //nCount连接数
HRESULT Init(CStringW strDataSource, CStringW strUserID, CStringW strPassWD, CStringW strCataLOG, int nCount = ){
HRESULT hr = S_OK;
ASSERT(nCount >= );
m_hSemaphore = ::CreateSemaphore(NULL, nCount, 0x7FFFFFFF, NULL); m_cs.Lock();
m_nMaxCount = nCount;
m_strDataSource = strDataSource;
m_strUserID = strUserID;
m_strPassWD = strPassWD;
m_strCataLOG = strCataLOG; for(int i=; i<m_nMaxCount; i++){
T* pConn = new T;
if (S_OK == (hr = pConn->Init(m_strDataSource, m_strUserID, m_strPassWD, m_strCataLOG))){
m_pConnList.push_back(pConn);
} else {
delete pConn;
break;
}
}
if(m_pConnList.size() != m_nMaxCount){
ASSERT();
}
m_cs.Unlock();
return hr;
} void Clear(){
if(m_hSemaphore)
{
::CloseHandle(m_hSemaphore);
m_hSemaphore = NULL;
} m_cs.Lock(); m_nMaxCount = ;
list<T*>::iterator it = m_pConnList.begin();
for(; it != m_pConnList.end(); it++)
{
T* pConn = *it;
if(pConn)
{
pConn->UnInit();
delete pConn;
}
}
m_pConnList.clear(); m_cs.Unlock();
} T* GetConnection(){
T* pConn = NULL;
if(::WaitForSingleObject(m_hSemaphore, INFINITE) != WAIT_OBJECT_0)
return pConn; m_cs.Lock();
if(!m_pConnList.empty())
{
pConn = m_pConnList.front();
m_pConnList.pop_front();
}
m_cs.Unlock(); if(pConn == NULL)
{
//create new database connection
pConn = new T();
HRESULT hr = NOERROR;
if(S_OK != (hr = pConn->Init(m_strDataSource, m_strUserID, m_strPassWD, m_strCataLOG))) {
delete pConn;
pConn = NULL;
}
}
return pConn;
}
void FreeConnection(T* pConn){
ASSERT(pConn != NULL); BOOL bSemaphore = FALSE; m_cs.Lock();
if(m_pConnList.size() >= m_nMaxCount)
{
pConn->UnInit();
delete pConn;
}
else
{
m_pConnList.push_back(pConn);
bSemaphore = TRUE;
}
m_cs.Unlock(); if(bSemaphore)
{
::ReleaseSemaphore(m_hSemaphore, , NULL);
}
} public:
BOOL ReOpenConnection(T* pConn){
return FALSE;
} BOOL VerifyConnection(T* pConn){
return TRUE;
} protected:
int m_nMaxCount;
CStringW m_strDataSource;
CStringW m_strUserID;
CStringW m_strPassWD;
CStringW m_strCataLOG;
CCriticalSection m_cs;
list<T*> m_pConnList; HANDLE m_hSemaphore;
//static CNativeClientOLEDBPool m_Instance;
}; #pragma once #include <list>
using namespace std; template <class T>
class CNativeClientOLEDBPool
{
public:
CNativeClientOLEDBPool(void){
m_hSemaphore = NULL;
m_nMaxCount = ;
}
~CNativeClientOLEDBPool(void){
Clear();
}
//static CNativeClientOLEDBPool* Instance() { return &m_Instance; } //nCount连接数
HRESULT Init(CStringW strDataSource, CStringW strUserID, CStringW strPassWD, CStringW strCataLOG, int nCount = ){
HRESULT hr = S_OK;
ASSERT(nCount >= );
m_hSemaphore = ::CreateSemaphore(NULL, nCount, 0x7FFFFFFF, NULL); m_cs.Lock();
m_nMaxCount = nCount;
m_strDataSource = strDataSource;
m_strUserID = strUserID;
m_strPassWD = strPassWD;
m_strCataLOG = strCataLOG; for(int i=; i<m_nMaxCount; i++){
T* pConn = new T;
if (S_OK == (hr = pConn->Init(m_strDataSource, m_strUserID, m_strPassWD, m_strCataLOG))){
m_pConnList.push_back(pConn);
} else {
delete pConn;
break;
}
}
if(m_pConnList.size() != m_nMaxCount){
ASSERT();
}
m_cs.Unlock();
return hr;
} void Clear(){
if(m_hSemaphore)
{
::CloseHandle(m_hSemaphore);
m_hSemaphore = NULL;
} m_cs.Lock(); m_nMaxCount = ;
list<T*>::iterator it = m_pConnList.begin();
for(; it != m_pConnList.end(); it++)
{
T* pConn = *it;
if(pConn)
{
pConn->UnInit();
delete pConn;
}
}
m_pConnList.clear(); m_cs.Unlock();
} T* GetConnection(){
T* pConn = NULL;
if(::WaitForSingleObject(m_hSemaphore, INFINITE) != WAIT_OBJECT_0)
return pConn; m_cs.Lock();
if(!m_pConnList.empty())
{
pConn = m_pConnList.front();
m_pConnList.pop_front();
}
m_cs.Unlock(); if(pConn == NULL)
{
//create new database connection
pConn = new T();
HRESULT hr = NOERROR;
if(S_OK != (hr = pConn->Init(m_strDataSource, m_strUserID, m_strPassWD, m_strCataLOG))) {
delete pConn;
pConn = NULL;
}
}
return pConn;
}
void FreeConnection(T* pConn){
ASSERT(pConn != NULL); BOOL bSemaphore = FALSE; m_cs.Lock();
if(m_pConnList.size() >= m_nMaxCount)
{
pConn->UnInit();
delete pConn;
}
else
{
m_pConnList.push_back(pConn);
bSemaphore = TRUE;
}
m_cs.Unlock(); if(bSemaphore)
{
::ReleaseSemaphore(m_hSemaphore, , NULL);
}
} public:
BOOL ReOpenConnection(T* pConn){
return FALSE;
} BOOL VerifyConnection(T* pConn){
return TRUE;
} protected:
int m_nMaxCount;
CStringW m_strDataSource;
CStringW m_strUserID;
CStringW m_strPassWD;
CStringW m_strCataLOG;
CCriticalSection m_cs;
list<T*> m_pConnList; HANDLE m_hSemaphore;
//static CNativeClientOLEDBPool m_Instance;
};
CNativeClientOLEDBPool.cpp 为空
查询数据的时候,就把会话创建出来,执行语句之后(可多次),释放会话.
pDB->CreateSessionAndCommand();
DWORD dwTick = ::GetTickCount();
m_lpData = pDB->FastQueryData(strSql, 17, &m_nDataLen, &m_nCount);
DWORD dwTick2 = ::GetTickCount();
pDB->ReleaseSessionAndCommand();
实测: 确实比ADO的要*倍以上.虽然比ADO访问上复杂一点.但你要懂了,也觉得很简单.
以上的封装只是针对某张表需要进行高速访问和插入来的.
查询的话.每张表都要写相对应的数据绑定. 当然你也可以在外层调用,自行绑定.哈哈~
后续:
后来我也进行了ODBC API的数据访问测试,效率跟OLEDB相差不多.
需要代码的话,我也可以贴出来.
目前微软已经不对OLEDB进行艮新了.但7年之内还是保持支持.
后续都会采用ODBC来访问数据库.
参考资料:
微软官方MSDN:https://msdn.microsoft.com/zh-cn/library/ms131687(v=sql.120).aspx
frank_liuxing博客:http://blog.csdn.net/frank_liuxing/article/details/43231233
我淋着雨博客:http://www.cnblogs.com/smartstone/archive/2006/04/23/383002.html
感谢这两位大牛.