MFC中使用ADO進行數據庫操做

參考FROM:http://hi.baidu.com/sunkanghome/item/e1fda510b3186359f1090ee2sql

數據庫與數據庫編程:

  • 當前各類主流數據庫有不少,包括Oracle, MS SQL Server, Sybase, Informix, MySQL, DB2, Interbase / Firebird, PostgreSQL, SQLite, SAP/DB, TimesTen, MS ACCESS等等。
  • 數據庫編程是對數據庫的建立、讀寫等一列的操做。數據庫編程分爲數據庫客戶端編程數據庫服務器端編程。數據庫客戶端編程主要使用ODBC API、ADO、ADO.NET、OCI、OTL等方法;數據庫服務端編程主要使用OLE DB等方法。
  • 數據庫編程須要掌握一些訪問數據庫技術方法,還須要注意怎麼設計高效的數據庫、數據庫管理與運行的優化、數據庫語句的優化。

ADO編程的通常步驟:

  1.   建立一個Connection對象  
  2.   打開數據源,創建同數據源的鏈接  
  3.   執行一個SQL命令 
  4.   使用結果集
  5.   終止鏈接

 

ADO最重要的三個對象:

  1. 鏈接對象(Connection)
  2. 命令對象(Command)
  3. 記錄集對象(RecordSet)

在使用這三個對象的時候,須要定義與之相對應的智能指針:_ConnectionPtr、_CommandPtr、_RecordsetPtr數據庫

使用智能指針要:定義指針變量、建立其實例(實例化)、調用方法和屬性。該智能指針在析構對象時,自動調用Release方法,即便用後不須要手動釋放內存,代碼更加簡潔。編程

但須要調用Close方法,關閉鏈接Connection或者記錄集RecordSet。安全

1、ADO編程預處理操做

1.1 導入ADO動態連接庫:

在工程的stdafx.h中加入以下語句:服務器

#import "c:\\Program Files\\Common Files\\System\\ADO\\msado15.dll" rename_namespace("ADOCG") rename("EOF","adoEOF") //rename("BOF","adoBOF") no_namespace
using namespace ADOCG;

注:import代碼要在一行中完成,換行需添加'\'ide

 

1.2 初始化OLE/COM庫環境:

在基於MFC的應用裏,在應用類的InitInstance成員函數中初始化OLE/COM庫環境,直接使用AfxOleInit,在退出應用時,該函數自動負責COM資源的釋放,比較方便,不用在函數

ExitInitInstance中添加相關操做:優化

BOOL CYourApp::InitInstance()
{
       AfxEnableControlContainer();
       //初始化OLE DLLs
       if(!AfxOleInit())
       {
           AfxMessageBox("初始化OLE DLL失敗!");
           Return FALSE;
        }
       ......
}

 

 

2、ADO進行數據庫鏈接:

2.1 在App類的頭文件中定義變量:

_ConnectionPtr m_pConnection;

2.2 建立智能指針的實例:

在App類的cpp文件InitInstance方法中:ui

m_pConnection.CreateInstance("ADODB.Connection"); //或者m_pConnection.CreateInstance(__uuidof(Connection));

使用'.'而不是->建立m_Connection實例,而後m_pConnection->open方法建立鏈接。spa

2.3 設置鏈接字符串,以便指定須要的鏈接

2.3.1 使用JET數據庫引擎實現對Acess2000類型的數據庫info.mdb的鏈接

CString strSQL=_T("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=info.mdb;User ID=admin;Passward=;");

2.3.2 使用OLE DB提供者實現對SQL Server的標準安全鏈接串

CString str SQL=_T("Provider=SQLOLEDB;Data Source=local;Initial Catalog=DVDRentDB_Data.MDF;User ID=sa;Password=123456;");

 或者是在此處不設置User ID和Password,而直接在Open的第二、3個參數中設置。

CString strConnection="Provider=SQLOLEDB;DataSource=local;Initial Catalog=DVDRentDB_Data.MDF";
m_pConnection->Open((_bstr_t)strSQL,"sa","820415",adModeUnknown);

注意:

  • 上面設置鏈接字符串的時候,若是過長鬚要分行時,則每一行都要加上雙引號,在最後加上分號便可。
  • 若是是本地服務器,則Data Source=loca l或 本地服務器名(主機名)
  • 若數據庫沒有設置密碼,在鏈接字符串中能夠將其省略,但User ID不能省
  • 若數據庫和程序文件不在同一文件夾下,直接寫數據庫名便可,在InitialCatalog中不需加上該數據庫的存儲器地址

2.3.3 使用OLE DB提供者實現對遠程SQL Server的標準安全鏈接串

strConnect=_T("Provider=sqloledb;Network Library=DBMSSOCN;"
              "Data Source=130.120.110.001,1433;"
              "Initial Catalog=MyDateBaseName;"
              "User ID=MyUserName;Password=MyPassword;");

2.4 實現對數據庫的鏈接

在ADO的操做中建議使用try...catch( )來捕獲錯誤信息,由於它有時會常常出現一些意想不到的錯誤

try
{
     m_pConnection->Open( (_bstr_t) strSQL," "," ",adModeUnknown);
}
catch(_com_error e)         //捕捉異常
{
     CString strError;
     strError.Format( "鏈接數據庫發生異常! \r \n錯誤信息:%s",e.ErrorMessage( ) );
     AfxMessageBox(errormessage);         //顯示錯誤信息
}

 綜上:InitInstance方法中可:

if(!AfxOleInit())
{
      AfxMessageBox("初始化OLE DLL失敗!");
      Return FALSE;
}
m_pConnection.CreateInstance("ADODB.Connection"); //或者m_pConnection.CreateInstance(__uuidof(Connection)); try   
{   
    m_pConnection->ConnectionTimeout = 3;
    //鏈接ACCESS2000   
    m_pConnection->Open("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=d:/Attendence/AttendenceDB.mdb","","",adModeUnknown);   
}   
catch(_com_error e) 
{   
    AfxMessageBox(e.Description() + _T("\n數據庫鏈接失敗"));   
}   

2.5 關閉數據庫鏈接

通常重載App類的ExitInstace( )函數,調用m_pConnection的Close方法關閉鏈接便可:

m_pConnection->Close( );
m_pConnection=NULL;

注意:因爲初始化COM庫調用的是AfxOleInit,這種方法初始化COM庫的優勢就在於資源的釋放也是自動進行的,因此沒必要擔憂資源泄漏的問題。

 

3、數據庫操做:

_CommandPtr接口

      該接口返回一個記錄集, 在使用_CommandPtr接口時,能夠利用全局_ConnectionPtr接口,也能夠在_CommandPtr接口裏直接使用鏈接串。若是隻執行一次或者幾回數據庫訪問操做,後者是比較好的選擇。可是,若是頻繁訪問數據庫,並要返回不少記錄集,那麼應該使用全局_ConnectionPtr接口建立一個數據庫鏈接,而後使用_CommandPtr接口執行存儲過程和SQL語句。

_RecordsetPtr接口

       該接口是一個記錄集對象, 與前兩種對象相比,它對記錄集提供了更多的控制功能,如記錄鎖定、遊標控制等。

3.1 使用Recordset對象操做數據庫:

假定已經使用鏈接指針m_pConnection對象建立了數據源的鏈接:

3.1.1 建立記錄集

 _RecordsetPtr    m_pRecordset;                    //聲明記錄集指針
 m_pRecordset.CreateInstance(__uuidof(Recordset)); //建立實例

3.1.2 打開記錄集

記錄集指針建立完畢後,調用該指針的Open方法打開記錄集。

//讀取數據庫:
CString sqlHasRecord;
sqlHasRecord.Format("SELECT * FROM WorkUser WHERE MemberID = '%s'" , m_StringNumber);
HRESULT hr = m_pRecordset->Open(  
                    sqlHasRecord.GetBuffer(0),
                    _variant_t((IDispatch*)theApp.m_pConnection, true),
                    adOpenDynamic,
                    adLockPessimistic,
                    adCmdText
                   );

Open函數聲明以下:

 HRESULT Recordset15::Open ( const _variant_t & Source,         //sql語句、表名、command對象 const _variant_t & ActiveConnection,   //已經創建好的鏈接  
                             enum CursorTypeEnum CursorType,      //用於設置在打開Recordset時提供者應使用的遊標類型,默認值adOpenForwardOnly enum LockTypeEnum LockType,        //用於設置在打開Recordset時提供者應使用的鎖定類型,默認值adLockReadOnly long Options ) ;              //獲取Source(即Open第一個參數)的方式

若是第一個參數是sql語句則選擇adCmdText

若是第一個參數是表名則選擇adCmdTable

//讀取數據庫:
CString sqlHasRecord;
sqlHasRecord.Format("SELECT * FROM WorkUser WHERE MemberID = '%s'" , m_StringNumber);
HRESULT hr = m_pRecordset->Open(sqlHasRecord.GetBuffer(0), _variant_t((IDispatch*)theApp.m_pConnection, true), adOpenDynamic, adLockPessimistic, adCmdText);

if (SUCCEEDED(hr))
{
    while (!m_pRecordset->adoEOF || !m_pRecordset->BOF)//遍歷返回的每一條記錄
    {
        CString m_StringID;
        m_StringID = (LPCSTR)_bstr_t(m_pRecordset->GetCollect("FeatureID"));//讀取id
     m_pRecordset->MoveNext();
} } m_pRecordset->Close(); //記錄用完以後須要關閉

 

3.1.3 遍歷記錄集

通常在返回記錄集時,一般要遍歷結果記錄集,以便查看或編輯某一條記錄:

注:爲了不發生異常:

MoveFirst、MovePrev以前,須要使用記錄集的指針BOF屬性來檢測當前的記錄集指針 是否位於第一條記錄以前;

MoveLast、MoveNext以前須要使用記錄集指針的EOF屬性來檢測當前的記錄集指針 是否位於最後一條記錄以後.

記錄集定位

兩種定位方法:前者經過設置或者獲取AbsolutePosition屬性,其值從1開始,而且當前記錄爲記錄集中第一條記錄時等於1, 後者經過設置或獲取BookMark屬性.

 

3.1.4 訪問記錄集

讀取字段值

m_pRecordset->GetCollect (字段名);    // 字符串 -> 字段名 or 整型(long) -> 字段對應的序號

設置字段值

m_pRecordset->PutCollect (字段名,新值);

//兩個方法的原型:
_variant_t GetCollect ( const _variant_t & Index )
void PutCollect ( const _variant_t & Index , const _variant_t &pvar )

 3.1.5 記錄集更新(添加、編輯、刪除)

 添加新的記錄:AddNew

 編輯當前記錄:Edit

 刪除當前記錄:Delete

AddNew方法:直接在表的末尾續加新記錄,該方法可使用參數,在參數中指定要添加的新紀錄;

                     也能夠不使用參數,而在後面使用PutCollect方法,並需使用Update函數保存新紀錄。

 Update方法:用於保存從調用AddNew方法以來所做的任何更改。

//在表的末尾增長新紀錄
        m_pRecordset->AddNew();
//------------------
        m_pRecordset->PutCollect("姓名",_variant_t(m_strName));
        m_pRecordset->PutCollect("工做單位",_variant_t(m_strComName));
        m_pRecordset->PutCollect("單位地址",_variant_t(m_strComAddr));
//------------------
        m_pRecordset->Update();//更新數據庫-將新紀錄存入數據庫

 

3.1.6 記錄集關閉

在對記錄集的操做完成後,必須及時關閉記錄集。

 if ( m_pRecordset != NULL )
 {
       m_pRecordset ->Close( );
       m_pRecordset =NULL;
 }

3.2 使用Connection對象操做數據庫

1.編輯SQL語句

2.執行connection對象的Excute()方法

//_ConnectionPt m_pConnection 智能指針對象
strSql.Format(_T("UPDATE WorkUser SET MemberName = '%s', MemberPosition = '%s' WHERE MemberID = '%s' "),m_StringName, m_StringPosition, m_StringNumber); try { m_pConnection->Execute(_bstr_t(strSql), 0, adCmdText); } catch(_com_error e) { MessageBox(e.Description()); return; }

 注:_variant_t和_bstr_t這兩個類分別封裝並管理VARIANT和BSTR這兩種數據類型,VARIANT和BSTR這兩種類型是COM中使用的數據類型。

      爲了C++中的變量應用到ADO編程中,只能進行數據類型的轉換。經過_variant_t和_bstr_t這兩個類,就能夠方便的把C++類型變量轉換成COM中的變量了。

4、實例演示

 4.1 初始化引入相關的庫+Connection對象的建立和數據庫的鏈接

#import "c:\\Program Files\\Common Files\\System\\ADO\\msado15.dll" rename_namespace("ADOCG") rename("EOF","adoEOF") //rename("BOF","adoBOF") 
using namespace ADOCG;
//... ... _ConnectionPtr m_pConnection;
//... ...
if(!AfxOleInit()) { AfxMessageBox("初始化OLE DLL失敗!"); Return FALSE; } m_pConnection.CreateInstance("ADODB.Connection"); try { m_pConnection->ConnectionTimeout = 3; //鏈接ACCESS2000 m_pConnection->Open("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=d:/Attendence/AttendenceDB.mdb","","",adModeUnknown); } catch(_com_error e) { AfxMessageBox(e.Description() + _T("\n數據庫鏈接失敗")); }

 4.2 Recordset對象的聲明與建立實例:

_RecordsetPtr m_pRecordset;
m_pRecordset.CreateInstance(__uuidof(Recordset)); //建立實例

 4.3 讀取記錄內容:

CString sqlHasRecord;
sqlHasRecord.Format("SELECT * FROM WorkUser WHERE MemberID = '%s'" , m_StringNumber);
HRESULT hr = m_pRecordset->Open(sqlHasRecord.GetBuffer(0), _variant_t((IDispatch*)theApp.m_pConnection, true), adOpenDynamic, adLockPessimistic, adCmdText);

if (SUCCEEDED(hr))
{
    while (!m_pRecordset->adoEOF || !m_pRecordset->BOF)//遍歷返回的每一條記錄
    {
        CString m_StringID;
        m_StringID = (LPCSTR)_bstr_t(m_pRecordset->GetCollect("FeatureID"));//讀取id
     m_pRecordset->MoveNext();
    }
}
m_pRecordset->Close();
//記錄用完以後須要關閉

 4.4 插入新記錄:

CString strSql;
strSql.Format("INSERT INTO WorkUser(MemberName, MemberID, MemberPosition, FeatureID, BeDeleted, SendedToClient) VALUES('%s', '%s', '%s', %d, 0, 0)",「ZhangSan」,」14S051000」, 「Student」, 16);
try
{

        (theApp.m_pConnection)->Execute(_bstr_t(strSql), 0, adCmdText);
}
catch(_com_error e)
{
        MessageBox(e.Description());
        return;
}

 4.5 更新記錄:

strSql.Format(_T("UPDATE WorkUser SET MemberName = '%s', MemberPosition = '%s' WHERE MemberID = '%s' "),m_StringName, m_StringPosition, m_StringNumber);
try
{

    (theApp.m_pConnection)->Execute(_bstr_t(strSql), 0, adCmdText);
}
catch(_com_error e)
{
    MessageBox(e.Description());
    return;
}

 4.6 刪除記錄:

CString strSql;
strSql.Format(_T("DELETE FROM WorkUser WHERE FeatureID = %s "), FeatureID[i]);
try
{
    (theApp.m_pConnection)->Execute(_bstr_t(strSql), 0, adCmdText);
}
catch(_com_error e)
{
    MessageBox(e.Description());
    return FALSE;
}

4.7 讀取字節流文件:

讀取圖像數據:

 

 try
 {
     CString sql;
     sql.Format("select * from WorkUser where MemberID='%s'",MemberID);

     HRESULT hr = m_pRecordset->Open(sql.GetBuffer(0),_variant_t((IDispatch *)theApp.m_pConnection,true),adOpenDynamic,adLockPessimistic,adCmdText);   
     if(SUCCEEDED(hr))        
     {   
         if(m_pRecordset->adoEOF||m_pRecordset->BOF)
         {

                MessageBox(_T("數據庫中沒有相應的記錄"));
                return;
         }
         else
         {
                long lDataSize = m_pRecordset->GetFields()->GetItem(imgColName.GetBuffer(0))->ActualSize;
                if (lDataSize>0)
                {
                    _variant_t          varBLOB;   
                    varBLOB = m_pRecordset->GetFields()->GetItem(imgColName.GetBuffer(0))->GetChunk(lDataSize);   
                    if(varBLOB.vt == (VT_ARRAY | VT_UI1))   
                    {   
                        if(buffer)                              ///從新分配必要的存儲空間   
                        {      
                            char *pBuf = NULL;   
                            SafeArrayAccessData(varBLOB.parray,(void **)&pBuf);   
                            memcpy(buffer,pBuf,lDataSize);                ///複製數據到緩衝區buffer   
                            SafeArrayUnaccessData (varBLOB.parray);   

                        }   
                    }   
                }
                else
                {                
                    MessageBox(_T("數據庫中的圖像數據爲空!"));
                    return;
                }
        }
     }   
 }
 catch (...)
 {
      MessageBox(_T("數據庫訪問出錯"));
 }
 m_pRecordset->Close();

 

 

 

4.8 保存字節流文件:

 

CString sql;
    sql.Format("select * from WorkUser where MemberID='%s'",MemberID);
    HRESULT hr = m_pRecordset->Open(sql.GetBuffer(0),_variant_t((IDispatch *)theApp.m_pConnection,true),adOpenDynamic,adLockPessimistic,adCmdText);   

    if(SUCCEEDED(hr))   
    {   
        if (!m_pRecordset->adoEOF||!m_pRecordset->BOF)
        {


            char            *pBuf = buffer;   
            VARIANT         varBLOB;   
            SAFEARRAY       *psa;   
            SAFEARRAYBOUND  rgsabound[1];   
            if(pBuf)   
            {       
                rgsabound[0].lLbound = 0;   
                rgsabound[0].cElements = bufLength;   
                psa = SafeArrayCreate(VT_UI1, 1, rgsabound);   //分配的數據類型爲unsigned int (1 byte 長度的類型)
                for (long i = 0; i < (long)bufLength; i++)   
                    SafeArrayPutElement (psa, &i, pBuf++);   

                varBLOB.vt = VT_ARRAY | VT_UI1;            
                varBLOB.parray = psa;   
                m_pRecordset->GetFields()->GetItem(imgColName.GetBuffer(0))->AppendChunk(varBLOB);   
            }   
            m_pRecordset->Update();   
        }
        else
        {
            MessageBox(_T("數據庫中沒有相應用戶的記錄!"));
            return;
        }

    }   
    m_pRecordset->Close();

 

 

 

 SafeArrayDestroy

相關文章
相關標籤/搜索