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 }  
發佈了16 篇原創文章 · 獲贊 9 · 訪問量 14萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章