1. 程式人生 > >事務對象和命令對象

事務對象和命令對象

star tle get const 註意 pro 選擇 false support


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命令對象的其他接口,得出數據源支持哪些接口。
這個例子非常簡單,只是為了演示如何創建會話對象和數據源對象罷了。
本節例子代碼


事務對象和命令對象