事務物件和命令物件

weixin_34247155發表於2018-01-21

title: 事務物件和命令物件
tags: [OLEDB, 資料庫程式設計, VC++, 資料庫]
date: 2018-01-21 09:22:10
categories: windows 資料庫程式設計
keywords: OLEDB, 資料庫程式設計, VC++, 資料庫


上次說到資料來源物件,這次接著說事務物件和命令物件。
事務是一種對資料來源的一系列更新進行分組或批處理以便當所有更新都成功時同時提交這些更新,或者如果任何一個更新失敗則不提交任何更新並且回滾整個事務的方法.
命令物件一般是用來執行sql語句並生成結果集的物件

會話物件

在OLEDB中通過以下3中方式支援事務:

  1. ITransactionLocal::StartTransaction
  2. ITransaction::commit
  3. ITransaction::Abort

OLEDB中定義事務和回話物件的介面如下:

CoType TSession {
   [mandatory]   interface IGetDataSource;
   [mandatory]   interface IOpenRowset;
   [mandatory]   interface ISessionProperties;
   [optional]    interface IAlterIndex;
   [optional]    interface IAlterTable;
   [optional]    interface IBindResource;
   [optional]    interface ICreateRow;
   [optional]    interface IDBCreateCommand;
   [optional]    interface IDBSchemaRowset;
   [optional]    interface IIndexDefinition;
   [optional]    interface ISupportErrorInfo;
   [optional]    interface ITableCreation;
   [optional]    interface ITableDefinition;
   [optional]    interface ITableDefinitionWithConstraints;
   [optional]    interface ITransaction;
   [optional]    interface ITransactionJoin;
   [optional]    interface ITransactionLocal;
   [optional]    interface ITransactionObject;
}

在建立了資料庫連線之後使用QueryInterface 查詢出IDBCreateSeesion物件,然後呼叫IDBCreateSession的CreateSession方法建立一個回話物件。
需要注意的是,一個資料來源連線可以建立多個回話物件,這裡只能通過這種方式建立回話物件,而不能直接通過CoCreateInstance 來建立。一般來說應用中至少建立一個會話物件

Command物件

Command物件的定義如下:

CoType TCommand {
   [mandatory]   interface IAccessor;
   [mandatory]   interface IColumnsInfo;
   [mandatory]   interface ICommand;
   [mandatory]   interface ICommandProperties;
   [mandatory]   interface ICommandText;
   [mandatory]   interface IConvertType;
   [optional]    interface IColumnsRowset;
   [optional]    interface ICommandPersist;
   [optional]    interface ICommandPrepare;
   [optional]    interface ICommandWithParameters;
   [optional]    interface ISupportErrorInfo;
   [optional]    interface ICommandStream;
}

一般建立Command物件是通過Session物件Query出來一個IDBCreateCommand介面讓後呼叫CreateCommand方法建立。
與會話物件相似,一個會話物件可以建立多個命令物件,但是從上面會話物件的定義可以看出IDBCreateCommand介面是一個可選介面,並不是所有的資料庫都支援,因此在建立命令物件的時候一定要注意判斷是否支援。對於不支援的可以採用其他辦法(一般採用直接開啟資料庫表的方式)。
下面是一個演示例子:

#define CHECK_OLEDB_INTERFACE(I, iid)\
    hRes = (I)->QueryInterface(IID_##iid, (void**)&(p##iid));\
    if(FAILED(hRes))\
    {\
        OLEDB_PRINTF(_T("不支援介面:%s\n"), _T(#iid));\
    }\
    else\
    {\
        OLEDB_PRINTF(_T("支援介面:%s\n"), _T(#iid));\
    }

BOOL CreateDBSession(IOpenRowset* &pIOpenRowset)
{
    DECLARE_BUFFER();
    DECLARE_OLEDB_INTERFACE(IDBPromptInitialize);
    DECLARE_OLEDB_INTERFACE(IDBInitialize);
    DECLARE_OLEDB_INTERFACE(IDBCreateSession);
    BOOL bRet = FALSE;
    HWND hDesktop = GetDesktopWindow();
    HRESULT hRes = CoCreateInstance(CLSID_DataLinks, NULL, CLSCTX_INPROC_SERVER, IID_IDBPromptInitialize, (void**)&pIDBPromptInitialize);
    OLEDB_SUCCESS(hRes, _T("建立介面IDBPromptInitialize失敗,錯誤碼:%08x\n"), hRes);
    
    hRes = pIDBPromptInitialize->PromptDataSource(NULL, hDesktop, DBPROMPTOPTIONS_WIZARDSHEET, 0, NULL, NULL, IID_IDBInitialize, (IUnknown**)&pIDBInitialize);
    OLEDB_SUCCESS(hRes, _T("彈出介面資料來源配置對話方塊失敗,錯誤碼:%08x\n"), hRes);
    
    hRes = pIDBInitialize->Initialize();
    OLEDB_SUCCESS(hRes, _T("連結資料庫失敗,錯誤碼:%08x\n"), hRes);

    hRes = pIDBInitialize->QueryInterface(IID_IDBCreateSession, (void**)&pIDBCreateSession);

    OLEDB_SUCCESS(hRes, _T("建立介面IDBCreateSession失敗,錯誤碼:%08x\n"), hRes);
    hRes = pIDBCreateSession->CreateSession(NULL, IID_IOpenRowset, (IUnknown**)&pIOpenRowset);
    OLEDB_SUCCESS(hRes, _T("建立介面IOpenRowset失敗,錯誤碼:%08x\n"), hRes);
    bRet = TRUE;

__CLEAR_UP:
    OLEDB_SAFE_RELEASE(pIDBPromptInitialize);
    OLEDB_SAFE_RELEASE(pIDBInitialize);
    OLEDB_SAFE_RELEASE(pIDBCreateSession);
    return bRet;
}

int _tmain(int argc, TCHAR *argv[])
{
    DECLARE_BUFFER();
    DECLARE_OLEDB_INTERFACE(IOpenRowset);
    DECLARE_OLEDB_INTERFACE(IDBInitialize);
    DECLARE_OLEDB_INTERFACE(IDBCreateCommand);

    DECLARE_OLEDB_INTERFACE(IAccessor);
    DECLARE_OLEDB_INTERFACE(IColumnsInfo);
    DECLARE_OLEDB_INTERFACE(ICommand);
    DECLARE_OLEDB_INTERFACE(ICommandProperties);
    DECLARE_OLEDB_INTERFACE(ICommandText);
    DECLARE_OLEDB_INTERFACE(IConvertType);
    DECLARE_OLEDB_INTERFACE(IColumnsRowset);
    DECLARE_OLEDB_INTERFACE(ICommandPersist);
    DECLARE_OLEDB_INTERFACE(ICommandPrepare);
    DECLARE_OLEDB_INTERFACE(ICommandWithParameters);
    DECLARE_OLEDB_INTERFACE(ISupportErrorInfo);
    DECLARE_OLEDB_INTERFACE(ICommandStream);
    
    CoInitialize(NULL);
    if (!CreateDBSession(pIOpenRowset))
    {
        OLEDB_PRINTF(_T("呼叫函式CreateDBSession失敗,程式即將推出\n"));
        return 0;
    }
    
    HRESULT hRes = pIOpenRowset->QueryInterface(IID_IDBCreateCommand, (void**)&pIDBCreateCommand);
    OLEDB_SUCCESS(hRes, _T("建立介面IDBCreateCommand失敗,錯誤碼:%08x\n"), hRes);
    
    hRes = pIDBCreateCommand->CreateCommand(NULL, IID_IAccessor, (IUnknown**)&pIAccessor);
    OLEDB_SUCCESS(hRes, _T("建立介面IAccessor失敗,錯誤碼:%08x\n"), hRes);

    CHECK_OLEDB_INTERFACE(pIAccessor, IColumnsInfo);
    CHECK_OLEDB_INTERFACE(pIAccessor, ICommand);
    CHECK_OLEDB_INTERFACE(pIAccessor, ICommandProperties);
    CHECK_OLEDB_INTERFACE(pIAccessor, ICommandText);
    CHECK_OLEDB_INTERFACE(pIAccessor, IConvertType);
    CHECK_OLEDB_INTERFACE(pIAccessor, IColumnsRowset);
    CHECK_OLEDB_INTERFACE(pIAccessor, ICommandPersist);
    CHECK_OLEDB_INTERFACE(pIAccessor, ICommandPrepare);
    CHECK_OLEDB_INTERFACE(pIAccessor, ICommandWithParameters);
    CHECK_OLEDB_INTERFACE(pIAccessor, ISupportErrorInfo);
    CHECK_OLEDB_INTERFACE(pIAccessor, ICommandStream);
    

__CLEAR_UP:
    OLEDB_SAFE_RELEASE(pIOpenRowset);
    OLEDB_SAFE_RELEASE(pIDBInitialize);
    OLEDB_SAFE_RELEASE(pIDBCreateCommand);

    OLEDB_SAFE_RELEASE(pIAccessor);
    OLEDB_SAFE_RELEASE(pIColumnsInfo);
    OLEDB_SAFE_RELEASE(pICommand);
    OLEDB_SAFE_RELEASE(pICommandProperties);
    OLEDB_SAFE_RELEASE(pICommandText);
    OLEDB_SAFE_RELEASE(pIConvertType);
    OLEDB_SAFE_RELEASE(pIColumnsRowset);
    OLEDB_SAFE_RELEASE(pICommandPersist);
    OLEDB_SAFE_RELEASE(pICommandPrepare);
    OLEDB_SAFE_RELEASE(pICommandWithParameters);
    OLEDB_SAFE_RELEASE(pISupportErrorInfo);
    OLEDB_SAFE_RELEASE(pICommandStream);
    CoUninitialize();
    return 0;
}

在上述的例子中,首先定義了一個巨集,用來判斷是否支援對應的介面。
同時定義了一個CreateDBSession方法來建立一個會話物件。在該函式中首先利用上一節的方法建立一個資料庫連線,然後在資料來源物件上呼叫QueryInterface來獲取介面IDBCreateSeesion,接著利用IDBCreateSeesion介面的CreateSeesion方法建立一個會話物件,由於IDBCreateCommand介面並不是所有的資料來源都支援,所以為了保證一定能建立會話物件,我們選擇會話物件必須支援的介面IOpenRowset。
在得到會話物件後,嘗試建立IDBCreateSession物件,如果它不支援,那麼程式直接退出。接著呼叫IDBCreateCommand介面來建立一個命令物件並嘗試query命令物件的其他介面,得出資料來源支援哪些介面。
這個例子非常簡單,只是為了演示如何建立會話物件和資料來源物件罷了。
本節例子程式碼
<hr />

相關文章