ADO數據庫編程 - 總結


一、數據庫操作准備

// ---------------------------------------------------------------------------------------------------------------------------------

1、導入ADO動態鏈接庫

  在工程的stdafx.h中加入如下語句:

  #import "C:\Program Files\Common Files\System\ado\msado15.dll"\        

  no_namespace   rename("EOF", "adoEOF")

  這一語句有何作用呢?        

  其最終作用同我們熟悉的 #include 類似,編譯的時候系統會為我們生成msado15.tlh和ado15.tli兩個C++頭文件來定義ADO庫,

  即加載ADO動態庫(msado15.dll)。        

  其中,no_namespace表明不使用命名空間,rename("EOF","adoEOF")表明把ADO中用到的EOF改為adoEOF,防止發生命名沖突。

  注意:

    該代碼需要在一行中完成,如果寫成兩行或者多行,行末要加上“\”符號,表示把這幾行看成一行,如本例。

 

// ---------------------------------------------------------------------------------------------------------------------------------

2、初始化OLE/COM庫環境

  在基於MFC的應用中初始化OLE/COM庫環境的一個比較好的位置,是在應用程序類CXXXApp的InitInstance成員函數中直接調用AfxOleInit(),

  而在退出應用時該函數也負責COM資源的釋放,將此函數添加在InitInstance中的如下位置:

BOOL CExpApp::InitInstance() {   AfxEnableControlContainer();   // 初始化OLE DLL 
  if (!AfxOleInit())   {     AfxMessageBox(_T("初始化OLE DLL失敗!"));     return FALSE;   }   // 其他操作...
 }

 

說明:        

  也可以在InitInstance中使用::CoInitialize初始化OLE/COM庫環境,        

   但須在ExitInitInstance中使用::CoUninitialize釋放占用的COM資源。        

  比較之下,顯然是使用AfxOleInit更為方便。

 

// ---------------------------------------------------------------------------------------------------------------------------------

 3、連接數據庫

  在Doc\View程序中,通常在應用程序類(CXXXApp)中進行數據庫的連接。  

  具體操作如下:       

  1)聲明一個Connection指針

    _ConnectionPtr m_pConnection;

    注:                    

      ADO最重要的對象有三個:                    

      連接對象(Connection)、命令對象(Command)和記錄集對象(RecordSet)。                    

      在使用這三個對象的時候,需要定義與之相對應的智能指針,分別為_ConnectionPtr、_CommandPtr、_RecordsetPtr。

      由上述ConnectionPtr指針的使用步驟可知,和C++中的類指針使用方法一樣,智能指針也要先定義指針變量、

      創建其實例(實例化),然后就可以調用它的方法和屬性。 不同的是,該智能指針最后是自動進行內存釋放的。

      所有的智能指針都是基於_com_ptr_t模板類的,該類封裝了IUnknow接口的3個方法:QueryInterface、Addref和Release。                    

      它具有自動計數的機制,即在構造對象時,自動為該對象計數加1。析構對象時,自動調用Release方法。                   

      (即該類型的指針在使用后不需要手動釋放內存)(但需要調用Close方法,關閉連接或者記錄集)                    

      所以智能指針會使代碼更加簡潔並且不易出錯。

  2)創建Connection對象            

    方法有如下兩種:

        m_pConnection.CreateInstance(__uuidof(Connection));                   

        m_pConnection.CreateInstance("ADODB.Connection");             

     注意:                  

        上面調用_ConnectionPtr接口指針的方法CreateInstance時,用的是"."而非"->"。

 

  3)設置連接字符串,以便指定需要的連接               

    對應不同的數據庫,其連接字庫串有所不同:               

     3.1) 使用JET數據庫引擎實現對Acess2000類型的數據庫info.mdb的連接

                      CString strSQ L= "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=info.mdb;User ID=admin;Passward=;";               

    或者                      

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

    3.2) 使用OLE DB提供者實現對SQL Server的標准安全連接串

       strConnect = _T("Provider=SQLOLEDB;Data Source=MyServerName;\

              Initial Catalog=MyDateBaseName;\

              User ID=MyUserName;Password=MyPassword;");               

      或者                     

      strConnect = _T("Provider=SQLOLEDB;Server=MyServerName;\

              Database=MyDateBaseName;\

              Uid=MyUserName;Pwd=MyPassword;");

               例程:              

      _bstr_t strConnect("Provider=SQLOLEDB;Server=MYSERVER;Database=MYDATADABE;Uid=sa;Pwd=12345678;");              

      m_pConnection->Open((_bstr_t)strSQL,"","",adModeUnknown);

              或者, 是在此處不設置User ID和Password,而直接在Open函數的第2、3個參數中設置,這也可以。

                _bstr_t strConnect("Provider=SQLOLEDB;Server=MYSERVER;Database=MYDATADABE;");              

      m_pConnection->Open((_bstr_t)strSQL,"sa","12345678",adModeUnknown);

    注意:     

      上面設置連接字符串的時候,如果過長需要分行時,可用反斜杠"\"。     

       如果是本地服務器,則DataSource=local或本地服務器名均可。     

      若數據庫沒有設置密碼,在連接字符串中可以將其省略,但User ID不能省。

      若數據庫和程序文件不在同一文件夾下,直接寫數據庫名即可,在InitialCatalog中不需加上該數據庫的存儲器地址。

 

     3.3) 使用OLE DB提供者實現對遠程SQL Server的標准安全連接串

      strConnec t= _T("Provider=sqloledb;Network Library=DBMSSOCN;\

              Data Source=130.120.110.001,1433;

              Initial Catalog=MyDateBaseName;

              User ID=MyUserName;Password=MyPassword;");

 

   4)、使用m_pConnection的Open方法實現對數據庫的連接

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

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

 

// ---------------------------------------------------------------------------------------------------------------------------------

4、關閉連接      

  一般重載App類的ExitInstace( )函數實現。      

  調用m_pConnection的Close方法關閉連接即可。      

  代碼如下:

             m_pConnection->Close( );             

    m_pConnection=NULL;

     注意:     

    由於初始化COM庫調用的是AfxOleInit,這種方法初始化COM庫的優點就在於資源的釋放也是自動進行的,所以不必擔心資源泄漏的問題。

 

 

 

二、數據庫操作 ADO庫中包含的三個基本接口為: _ConnectionPtr接口、_CommandPtr接口、_RecordsetPtr接口。

// ---------------------------------------------------------------------------------------------------------------------------------
1、_ConnectionPtr接口        

   該接口返回一個記錄集或一個空指針。        

   通常用它來創建一個數據庫連接,或執行一條不返回任何結果的SQL語句,如一個存儲過程。       

   不推薦使用_ConnectionPtr接口返回一個記錄集,對於要返回記錄集的操作通常用_RecordsetPtr來實現。       

   而且使用_ConnectionPtr時要想得到記錄數目必須遍歷所有記錄,但使用_RecordsetPtr時則不需要。

 

// ---------------------------------------------------------------------------------------------------------------------------------

2、_CommandPtr接口       

  該接口返回一個記錄集。       

  它提供了一種簡單的方法來執行返回記錄集的存儲過程和SQL語句。       

  在使用_CommandPtr接口時,可以利用全局_ConnectionPtr接口,也可以在_CommandPtr 接口里直接使用連接串。

  如果只執行一次或者幾次數據庫訪問操作,后者是比較好的選擇。       

  但是,如果頻繁訪問數據庫,並要返回很多記錄集,那么應該使用全局_ConnectionPtr接口創建一個數據庫連接,然后使用_CommandPtr接口執行存儲過程和SQL語句。

// ---------------------------------------------------------------------------------------------------------------------------------

3、_RecordsetPtr接口       

  該接口是一個記錄集對象。       

  與前兩種對象相比,它對記錄集提供了更多的控制功能,如記錄鎖定、游標控制等。       

  同_CommandPtr接口一樣,它不一定使用一個已經創建的數據庫連接,可以用一個連接串代替連接指針賦給_RecordsetPtr的connection成員變量,讓它自己創建數據庫連接。       

   如果使用多個記錄集,最好的方法是同Command對象一樣使用已經創建了數據連接的全局_ConnectionPtr接口,然后使用_RecordsetPtr執行存儲過程和SQL語句。

        注意:        

  可以使用Recordset對象來執行查詢命令,但如果查詢或者存儲過程是需要參數的,這時就只能使用Command對象。

  使用Recordset對象操作數據庫:

   假定已經成功使用Connection對象創建了數據源的連接,連接指針為m_pConnection

 

  1)創建記錄集

     _RecordsetPtr    m_pRecordset;                // 聲明記錄集指針                   

    m_pRecordset.CreateInstance(__uuidof(Recordset));   // 創建記錄集        

  或者:                           

    _RecordsetPtr    m_pRecordset;                // 聲明記錄集指針                  

    m_pRecordset.CreateInstance("ADODB.Recordset");   // 創建記錄集

 

  2)打開記錄集         

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

  該函數聲明如下:             

    HRESULT Recordset15::Open(const _variant_t & Source,                                                        

                  const _variant_t & ActiveConnection,

                  enum CursorTypeEnum CursorType,

                  enum LockTypeEnum LockType,

                  long Options);        

    各個參數的含義如下:

    參數Source:                   

      為_variant_t類型的引用,可以為有效的Command對象、SQL語句、表名、存儲過程調用等。    

    參數ActiveConnection: 

      為_variant_t類型的引用,為已經建立好的連接。    

    參數CursorType:           

      用於設置在打開Recordset時提供者應使用的游標類型,它可取CursorTypeEnum 中的任一值,默認值為adOpenForwardOnly。    

     參數 LockType:             

      用於設置在打開Recordset時提供者應使用的鎖定類型,它可取枚舉LockTypeEnum中的任一值,默認值為adLockReadOnly。    

     參數 Options:               

      用於設置獲取Source(即Open第一個參數)的方式,其類型long。

          

例程1:          

   CString strSQL = "select * from mytablename";          

   m_pRecordset->Open(_variant_t (strSQL), 

             m_pConnection.GetInterfacePtr( ),

             adOpenDynamic, 

             adLockOptimistic,                                              

             adCmdText);          

使用SQL語句作為Open方法的第一個參數Source的值,此時Options為adCmdText

 

例程2:             

  m_pRecordset->Open(_variant_t ("tbDVDInfo"),                                               

             m_pConnection.GetInterfacePtr( ),                                               

               adOpenDynamic,                                               

            adLockOptimistic,                                               

            adCmdTable);         

  直接使用表名作為第一個參數,此時Options應為adCmdTable

 

  3)遍歷記錄集          

  一般在返回記錄集時,通常要遍歷結果記錄集,以便查看或編輯某一條記錄,Recoreset指針提供了幾個用於實現遍歷的方法。

  注意:    

    為了避免發生異常,一般在使用MoveFirst、MovePrev之前,需要使用記錄集的指針BOF屬性來檢測當前的記錄集指針是否位於第一條記錄之前;    

    在使用MoveLast、MoveNext之前需要使用記錄集指針的EOF屬性來檢測當前的記錄集指針是否位於最后一條記錄之后。

 

  4)記錄集定位          

  記錄集接口類提供了兩種定位方法: 絕對定位和書簽定位

  前者通過設置或者獲取AbsolutePosition屬性即可,其值從1開始,並且當前記錄為記錄集中第一條記錄時等於1                

  對於后者可以通過設置或獲取BookMark屬性即可。

 

   5)訪問記錄集         

  讀寫記錄集中某一記錄中的一個字段,有具體有兩種方法:

  一:

  讀取操作:

      _variant_t   var = m_pResultSet->Fields->GetItem(_variant_t("字段名"))->Value;

         也可用GetValue方法:

       _variant_t   var = m_pResultSet->Fields->GetItem(_variant_t("字段名"))->GetValue();

  寫入操作:

      _variant_t   var = .....   // 初始化

      m_pResultSet->Fields->GetItem(_variant_t("字段名"))->Value = var;

    也可用PutValue方法:

      m_pResultSet->Fields->GetItem(_variant_t("字段名"))->PutValue(var);

  二:

  最簡單的方法是直接使用如下語句:

  讀取操作:    

        _variant_t   var =  m_pRecordset->GetCollect (_variant_t("字段名"));

  寫入操作:

        _variant_t   var = ...  // 初始化                   

        m_pRecordset->PutCollect (_variant_t("字段名"), var);

 

         兩個方法的原型:                  

      _variant_t GetCollect(const _variant_t & Index )                  

       void  PutCollect(const _variant_t & Index, const _variant_t &pvar)

         其中:         

      參數Index可以是字符串表示字段名,也可以是整型,表示字段對應的序號。         

      pvar表示要寫入的變量值。

  例如:         

    _variant_t var;         

    var = m_pRentRecordset->GetCollect(_variant_t("ID"));         

    var = m_pRentRecordset->GetCollect(long(0));   // 都可以

 

  6)記錄集更新               

  更新記錄集包括添加新的記錄、編輯當前記錄和刪除當前記錄               

   記錄集接口指針對這三種操作分別提供了相應的方法

  添加新的記錄:AddNew               

  編輯當前記錄:Edit               

  刪除當前記錄:Delete

  注意:                  

  記錄集接口指針針對AddNew以及Edit方法提供了Update方法,用於在數據庫中更新新添加或者編輯后的記錄。

  AddNew方法:                       

    用於添加新紀錄(該添加是直接在表的末尾續加的),該方法可以使用參數,在參數中指定要添加的新紀錄;  

    也可以不使用參數,而在后面使用PutCollect方法,並需使用Update函數保存新紀錄。

  Update方法:

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

   例程:                   

    //在表的末尾增加新紀錄                  

    m_pRecordset->AddNew();                  

     m_pRecordset->PutCollect(_variant_t("姓名"),         

    _variant_t(m_strName));                  

     m_pRecordset->PutCollect(_variant_t("工作單位"),   _variant_t(m_strComName));                  

    m_pRecordset->PutCollect(_variant_t("單位地址"),   _variant_t(m_strComAddr));

    //更新數據庫-將新紀錄存入數據庫                  

    m_pRecordset->Update();

 

  7)記錄集關閉

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

  if ( m_pRecordset != NULL )               

  {                        

     m_pRecordset ->Close( );                        

    m_pRecordset =NULL;               

   }

 

三、ADO中的數據類型           

  在使用ADO技術操作數據庫時,存取變量的數據類型都是COM類型,這就要求經常在COM類型和普通數據類型之間進行類型轉換。        

  ADO中特有的數據類型包括以下三種:

  // ---------------------------------------------------------------------------------------------------------------------------------

   1、Variant         

     該類型是結構化的數據類型,它包含值成員和數據類型成員。

    Variant可以包含許多其他的數據類型:如Variant、BSTR、Boolean、IDispatch或者IUnknow指針、貨幣、日期等。        

    COM中由_variant_t 類來封裝和管理Variant數據類型。        

    在使用ADO對象模型操作數據庫時,如果對象的某個方法或者屬性操作數接受某個值,那么通常表明該值在_variant_t 中傳遞。

  注意:            

     在利用ADO對象進行C++數據類型的相關數據庫操作(如將CString類型的值添加到數據庫)時,需要進行強制類型轉換            

  例如:             

    對於  CString m_strName;                            

         m_pRecordset->PutCollect("姓名", _variant_t(m_strName));

 

  // ---------------------------------------------------------------------------------------------------------------------------------

  2、BSTR               

   該類型 ( Basic STRing )也是結構化的數據類型,它包含字符串和字符串的長度。             

   COM提供分配、處理和釋放BSTR的方法,由_bstr_t類來封裝和管理BSTR數據類型          

   在使用ADO對象模型操作數據庫時,如果對象的某個方法或者屬性操作數接受一個字符串值,那么通常表明該值的形式為_bstr_t,而非一般的CString。

 

  // ---------------------------------------------------------------------------------------------------------------------------------

  3、SafeArray         同樣是一種結構化的數據類型,包含其它數據類型的數組。        

  在使用ADO對象模型操作數據庫時,如果對象的某個方法或者屬性操作數接受或者返回一個數組,則數組類型只能是SafeArray,而非通常意義上的C/C++數組。

  通常,從數據庫中取出的字段值大都在_variant_t中傳遞,下面給出從COM類型Variant向CString類型轉換的通用函數。        

  該函數將為數據庫的訪問和操作提供極大便利。

 

 1 CString    CLeftTreeView::VariantToCString(const _variant_t &var)  2 {  3  CString strValue;  4     switch (var.vt)  5  {  6     case VT_BSTR:    //字符串 
 7     case VT_LPSTR:  8     case VT_LPWSTR:  9         strValue = (LPCTSTR)(_bstr_t)var; 10         break; 11     case VT_I1:        //無符號字符 
12     case VT_UI1: 13         strValue.Format("%d", var.bVal); 14         break; 15     case VT_I2:        //短整型 
16         strValue.Format("%d", var.iVal); 17         break; 18     case VT_UI2:    //無符號短整型 
19          strValue.Format("%d", var.uiVal); 20          break; 21     case VT_INT:    //整型 
22         strValue.Format("%d", var.intVal); 23         break; 24     case VT_I4:        //整型 
25     case VT_I8:        //長整型 
26         strValue.Format("%d", var.lVal); 27         break; 28     case VT_UINT:    //無符號整型 
29         strValue.Format("%d", var.uintVal); 30         break; 31     case VT_UI4:    //無符號整型 
32     case VT_UI8:    //無符號長整型 
33         strValue.Format("%d", var.ulVal); 34         break; 35     case VT_VOID: 36         strValue.Format("%8x", var.byref); 37         break; 38     case VT_R4:        //浮點型 
39         strValue.Format("%.4f", var.fltVal); 40         break; 41     case VT_R8:        //雙精度型 
42         strValue.Format("%.8f", var.dblVal); 43         break; 44     case VT_DECIMAL://小數 
45         strValue.Format("%.8f", (double)var); 46         break; 47     case VT_CY: 48  { 49             COleCurrency cy = var.cyVal; 50             strValue = cy.Format(); 51  } 52         break; 53     case VT_BLOB: 54     case VT_BLOB_OBJECT: 55     case 0x2011: 56         strValue = "[BLOB]"; 57         break; 58     case VT_BOOL:    //布爾型 
59         strValue = var.boolVal ? "TRUE" : "FALSE"; 60         break; 61     case VT_DATE:    //日期型 
62  { 63             DATE dt = var.date; 64             COleDateTime da = COleDateTime(dt); 65             strValue = da.Format("%Y-%m-%d %H:%M:%S"); 66  } 67         break; 68     case VT_NULL:    //NULL值 
69     case VT_EMPTY:    //
70         strValue = ""; 71         break; 72     case VT_UNKNOWN://未知類型 
73     default: 74         strValue = "UN_KNOW"; 75          break; 76  } 77     return strValue; 78 }  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM