Visual C++數據庫編程(ODBC)



ODBC基本概念

 

ODBC(Open Database Connectivity,開放數據庫互連)是微軟公司開放服務結構(WOSAWindows Open Services Architecture)中有關數據庫的一個組成部分,它建立了一組規范,並提供了一組對數據庫訪問的標准API(應用程序編程接口)。這些API利用SQL來完成其大部分任務。ODBC本身也提供了對SQL語言的支持,用戶可以直接將SQL語句送給ODBC

  一個基於ODBC的應用程序對數據庫的操作不依賴任何DBMS,不直接與DBMS打交道,所有的數據庫操作由對應的DBMSODBC驅動程序完成。也就是說,不論是FoxProAccess還是Oracle數據庫,均可用ODBC API進行訪問。由此可見,ODBC的最大優點是能以統一的方式處理所有的數據庫。

  一個完整的ODBC由下列幾個部件組成:

  應用程序(Application)

  ODBC管理器(Administrator)。該程序位於Windows 95控制面板(Control Panel)32ODBC內,其主要任務是管理安裝的ODBC驅動程序和管理數據源。

  驅動程序管理器(Driver Manager)。驅動程序管理器包含在ODBC32.DLL中,對用戶是透明的。其任務是管理ODBC驅動程序,是ODBC中最重要的部件。

  ODBC API

  ODBC 驅動程序。是一些DLL,提供了ODBC和數據庫之間的接口。

  數據源。數據源包含了數據庫位置和數據庫類型等信息,實際上是一種數據連接的抽象。

各部件之間的關系如圖下圖所示:

應用程序要訪問一個數據庫,首先必須用ODBC管理器注冊一個數據源,管理器根據數據源提供的數據庫位置、數據庫類型及ODBC驅動程序等信息,建立起ODBC與具體數據庫的聯系。這樣,只要應用程序將數據源名提供給ODBCODBC就能建立起與相應數據庫的連接。

  在ODBC中,ODBC API不能直接訪問數據庫,必須通過驅動程序管理器與數據庫交換信息。驅動程序管理器負責將應用程序對ODBC API的調用傳遞給正確的驅動程序,而驅動程序在執行完相應的操作后,將結果通過驅動程序管理器返回給應用程序。

  在訪問ODBC數據源時需要ODBC驅動程序的支持。用Visual C++ 5.0安裝程序可以安裝SQL Server Access Paradox dBase FoxPro Excel Oracle Microsoft Text等驅動程序.在缺省情況下,VC5.0只會安裝SQL Server Access FoxProdBase的驅動程序.如果用戶需要安裝別的驅動程序,則需要重新運行VC 5.0的安裝程序並選擇所需的驅動程序。 

 

 

 

ADO對象訪問模型

本節簡要介紹了微軟的活動數據對象(ADO)模型,結合實例闡述了在Visual C++環境下使用ADO操縱數據庫的基本步驟,分析ADO的特點及與開放式數據庫連接(ODBC)的差異與應用前景。

關鍵詞: 活動數據對象 數據庫 Visual C++

ADO是微軟整個COM戰略體系中的一個組成部分

  活動數據對象(ADO)是一組由微軟提供的COM組件。 ADO建立在微軟所提倡的COM體系結構之上,它的所有接口都是自動化接口,因此在C++、VisualBasic、Delphi等支持COM的開發語言中通過接口都可以訪問到ADO。ADO通過使用OLE DB這一新技術實現了以相同方式可以訪問關系數據庫、文本文件、非關系數據庫、索引服務器和活躍目錄服務等的數據,擴大了應用程序中可使用的數據源范圍,從而成為微軟整個COM戰略體系中訪問數據源組件的首選,是ODBC的替代產品。 

 

ADO對象模型組成
  與微軟的其它數據訪問模型DAO和RDO相比,ADO對象模型非常精煉,僅由三個主要對象Connection、Command、Recordset和幾個輔助對象組成,其相互關系如圖所示。Connection對象提供OLE DB數據源和對話對象之間的關聯,它通過用戶名稱和口令來處理用戶身份的鑒別,並提供事務處理的支持;它還提供執行方法,從而簡化數據源的連接和數據檢索的進程。Command對象封裝了數據源可以解釋的命令,該命令可以是SQL命令、存儲過程或底層數據源可以理解的任何內容。Record set用於表示從數據源中返回的表格數據,它封裝了記錄集合的導航、記錄更新、記錄刪除和新記錄的添加等方法,還提供了批量更新記錄的能力。其它輔助對象則分別提供封裝ADO錯誤、封裝命令參數和封裝記錄集合的列。 

ADO的特點分析

  (1)由於封裝了許多底層工作,使用ADO與使用ODBC幾乎是一樣方便。

  (2) ADO不僅具有ODBC的主要功能,而且ADO適用的數據源的范圍要大的多。

  (3)在定義ADO記錄集變量和數據庫表字段綁定類時,要求記錄集的字段變量、狀態變量與數據庫表字段的個數、順序必須相同。這一點比在FMC中使用ODBC要復雜一些。但在數據庫字段與ADO記錄集字段變量綁定的宏中,ADO 提供的數據類型要遠多於FMC中的RFX(如日期時間類型,在ODBC中只能轉換為Cstring類型)。

  (4)ADO允許同一Connection實例下有多個Record set實例。

  (5)ADO允許進行批更新(使用的Update Batch方法),這樣將大大減輕網絡負擔,提高數據庫處理效率。

 4 ADO在Visual C++中的使用

  利用微軟在Micrsoft Studio 6中提供的ADO2,可以在Visual C++中使用ADO接口操縱SQL SERVER數據庫。在編譯型高級語言中使用ADO,比起在一些腳本語言(如Visual Basic Scropt和JavaScript)中使用ADO要困難一些。

  以下給出一個Visual C++下使用ADO的Connection對象及其Record set對象的基本步驟:

  (1) 使用import指令引入ADO2組件

  例:#import "C:\ADO\msado15.dll" no_namespace rename("EOF", "EndOfFile") 

  (2) 定義CADORecordBinding 的派生類,用於程序與數據庫表字段的交互,該類的定義可參見icrsint.h。

  例:

class CIntlive public CADORecordBinding 

public:
DBTIMESTAMP m_datetime; //定義ADO記錄集字段變量(與數據庫表字段相對應)
long m_key;
long m_value;
long m_quality;
WORD m_stsdatetime; //定義ADO記錄集狀態變量
WORD m_stskey;
WORD m_stsvalue;
WORD m_stsquality;
BEGIN_ADO_BINDING(CIntlive) //將數據庫字段與ADO記錄集字段變量綁定
ADO_VARIABLE_LENGTH_ENTRY2(1,adDBTimeStamp,m_datetime,sizeof(m_datetime),m_stsdatetime,true)
ADO_NUMERIC_ENTRY(2,adInteger,m_key,10,0,m_stskey,true)
ADO_NUMERIC_ENTRY(3,adInteger,m_value,10,0,m_stsvalue,true)
ADO_NUMERIC_ENTRY(4,adInteger,m_quality,10,0,m_stsquality,true)
END_ADO_BINDING()
};

  (3) 調用CoInitialize初始化COM ::CoInitialize(NULL); 

  (4) 聲明ADO的Connection對象指針和Recordset對象指針並初始化。(類型名在 msado15.dll中已定義)

  例:

_ConnectionPtr pConnection1 NULL;
_RecordsetPtr rstADO1 NULL; 

  (5) 定義CADORecordBinding派生類的實例及其Bind接口指針。

  例:

CIntlive m_intdata; 
IADORecordBinding *rstADOBind1 NULL; 

  (6) 產生Connection對象實例和Record set對象實例。

  例:

pConnection1.CreateInstance(_uuidof(Connection)); 
rstADO1.CreateInstance(__uuidof(Recordset)) 

  (7) 連接到數據庫並打開Record set對象,其中open函數的參數的使用方法可參見微軟MSDN中ADO 相應對象參數的Basic描述。

  例:

PConnection1->Open("driver={SQL server};server=servera;uid=sa;pwd=;database=pubs","","",NULL);
rstADO1->Open("data", _variant_t((IDispatch *)pConnection1,true), 
adOpenKeyset,adLockBatchOptimistic, adCmdTable); 

  (8) 將CADORecordBinding派生類的實例聯編到Record set對象的Bind接口。

  例:

RstADOBind1->BindToRecordset(&m_intdata); 

  (9) 對Record set對象實例進行操作。操作方法可參見微軟MSDN中ADO Record set對象相應方法的Basic描述。

   例:

rstADO1->Move Next(); //移動游標到下一條記錄
rstADO1->Update(_variant_t("quality"),_variant_t("3"))); //修改記錄的quality字段的值為3
rstADO1->Update Batch(adAffectAll)); //將在Record set對象上的所有更新一次送入數據庫

  (10) 關閉Record set對象並釋放Bind接口。

  例:

RstADO1->Close(); 
RstADOBind2->Release(); 

  (11) 關閉連接 pConnection1->Close(); 

  (12) 調用CoUnitialize釋放COM資源 ::CoUninitialize(); 

結論

  作為ODBC的替代產品,ADO確實有其過人之處。由於ADO數據源幾乎覆蓋了目前常見的數據源類型,對於ODBC所不支持的數據源,ADO無疑是唯一的選擇。而ADO的批更新功能,更是網絡環境下大數據量更新應用的重要因素。由於ADO缺乏大量的第三方廠商的支持,使得ADO目前遠不如ODBC普及,但其面向對象的特性將使ADO具有比較廣闊的發展前景。

 

ODBC編程實例

 

Microsoft Developer Studio為大多數標准的數據庫格式提供了32位ODBC驅動器。這些標准數據格式包括有:SQL Server、Access、Paradox、dBase、FoxPro、Excel、Oracle以及Microsoft Text。如果用戶希望使用其他數據格式,則需要安裝相應的ODBC驅動器及DBMS。

  用戶使用自己的DBMS數據庫管理功能生成新的數據庫模式后,就可以使用ODBC來登錄數據源。對用戶的應用程序來說,只要安裝有驅動程序,就能注冊很多不同的數據庫。登錄數據庫的具體操作參見有關ODBC的聯機幫助。 

  一、MFC提供的ODBC數據庫類

  Visual C++的MFC基類庫定義了幾個數據庫類。在利用ODBC編程時,經常要使用到 CDatabase(數據庫類)、CRecordSet(記錄集類)和CRecordView(可視記錄集類)。

  CDatabase類對象提供了對數據源的連接,通過它可以對數據源進行操作。

  CRecordSet類對象提供了從數據源中提取出的記錄集。CRecordSet對象通常用於兩種形式:動態行集(dynasets)和快照集(snapshots)。動態行集能與其他用戶所做的更改保持同步,快照集則是數據的一個靜態視圖。每種形式在記錄集被打開時都提供一組記錄,所不同的是,當在一個動態行集里滾動到一條記錄時,由其他用戶或應用程序中的其他記錄集對該記錄所做的更改會相應地顯示出來。

  CRecordView類對象能以控件的形式顯示數據庫記錄,這個視圖是直接連到一個CRecordSet對象的表視圖。

  二、應用ODBC編程

  應用Visual C++的AppWizard可以自動生成一個ODBC應用程序框架,步驟是:打開File菜單的New選項,選取Projects,填入工程名,選擇MFC AppWizard (exe),然后按AppWizard的提示進行操作。

  當AppWizard詢問是否包含數據庫支持時,如果想讀寫數據庫,那么選定Database view with file support;如果想訪問數據庫的信息而不想寫回所做的改變,那么選定Database view without file support。

  選好數據庫支持之后,Database Source 按鈕會被激活,選中它去調用Data Options對話框。在Database Options對話框中會顯示出已向ODBC注冊的數據庫資源,選定所要操作的數據庫,如:Super_ES,單擊OK后出現Select Database Tables對話框,其中列舉了選中的數據庫包含的全部表;選擇要操作的表后,單擊OK。在選定了數據庫和數據表之后,就可以按照慣例繼續進行AppWizard操作。

  特別需要指出的是:在生成的應用程序框架View類(如:CSuper_ESView)中,包含一個指向CSuper_ESSet對象的指針m_pSet,該指針由AppWizard建立,目的是在視表單和記錄集之間建立聯系,使得記錄集中的查詢結果能夠很容易地在視表單上顯示出來。

  要使程序與數據源建立聯系,需用CDateBase::OpenEx()或CDatabase::Open()函數來進行初始化。數據庫對象必須在使用它構造記錄集對象之前初始化。

 三、實例

  1.查詢記錄

  查詢記錄使用CRecordSet::Open()和CRecordSet::Requery()成員函數。在使用CRecordSet類對象之前,必須使用CRecordSet::Open()函數來獲得有效的記錄集。一旦已經使用過CRecordSet::Open()函數,再次查詢時就可以應用CRecordSet::Requery()函數。

  在調用CRecordSet::Open()函數時,如果將一個已經打開的CDatabase對象指針傳給CRecordSet類對象的m_pDatabase成員變量,則使用該數據庫對象建立ODBC連接;否則如果m_pDatabase為空指針,就新建一個CDatabase類對象,並使其與缺省的數據源相連,然后進行CRecordSet類對象的初始化。缺省數據源由GetDefaultConnect()函數獲得。也可以提供所需要的SQL語句,並以它來調用CRecordSet::Open()函數,例如:Super_ESSet.Open(AFX_DATABASE_USE_DEFAULT,strSQL);

  如果沒有指定參數,程序則使用缺省的SQL語句,即對在GetDefaultSQL()函數中指定的SQL語句進行操作:

  CString CSuper_ESSet::GetDefaultSQL()
  {return _T(″[BsicData],[MinSize]″);}


  對於GetDefaultSQL()函數返回的表名,對應的缺省操作是SELECT語句,即:

  SELECT *FROM BasicData,MainSize


  在查詢過程中,也可以利用CRecordSet的成員變量m_strFilter和m_strSort來執行條件查詢和結果排序。m_strFilter為過濾字符串,存放着SQL語句中WHERE后的條件串;m_strSort為排序字符串,存放着SQL語句中ORDER BY后的字符串。如:

  Super_ESSet.m_strFilter=″TYPE=‘電動機’″;
  Super_ESSet.m_strSort=″VOLTAGE″;
  Super_ESSet.Requery();


  對應的SQL語句為:

  SELECT *FROM BasicData,MainSize
  WHERE TYPE=‘電動機’
  ORDER BY VOLTAGE


  除了直接賦值給m_strFilter以外,還可以使用參數化。利用參數化可以更直觀、更方便地完成條件查詢任務。使用參數化的步驟如下:

  S聲明參變量:

  CString p1;
  float p2;


  S在構造函數中初始化參變量:

  p1=_T(″″);
  p2=0.0f;
  m_nParams=2;


  S將參變量與對應列綁定:

  pFX->SetFieldType(CFieldExchange::param)

  RFX_Text(pFX,_T(″P1″),p1);
  RFX_Single(pFX,_T(″P2″),p2);


  完成以上步驟后就可以利用參變量進行條件查詢:

  m_pSet->m_strFilter=″TYPE=? AND VOLTAGE=?″;m_pSet->p1=″電動機″;
  m_pSet->p2=60.0; 
  m_pSet->Requery();


  參變量的值按綁定的順序替換查詢字串中的“?”通配符。

  如果查詢的結果是多條記錄,可以用CRecordSet類的函數Move()、MoveNext()、MovePrev()、MoveFirst()和MoveLast()來移動光標。

  2.增加記錄

  增加記錄使用AddNew()函數,要求數據庫必須是以允許增加的方式打開:

  m_pSet->AddNew(); //在表的末尾增加新記錄
  m_pSet->SetFieldNull(&(m_pSet->m_type), FALSE);
  m_pSet->m_type=″電動機″;
  ……
  //輸入新的字段值
  m_pSet->Update();
  //將新記錄存入數據庫
  m_pSet->Requery();
  //重建記錄集


  3.刪除記錄

  可以直接使用Delete()函數來刪除記錄,並且在調用Delete()函數之后不需調用Update()函數:

  m_pSet->Delete();
  if (!m_pSet->IsEOF())
  m_pSet->MoveNext();
  else
  m_pSet->MoveLast();


  4.修改記錄

  修改記錄使用Edit()函數:

  m_pSet->Edit();
  //修改當前記錄
  m_pSet->m_type=″發電機″;
  //修改當前記錄字段值
 ……
  m_pSet->Update(); //將修改結果存入數據庫
  m_pSet->Requery();


  5.撤消操作

  如果用戶選擇了增加或者修改記錄后希望放棄當前操作,可以在調用Update()函數之前調用:

  CRecordSet::Move(AFX_MOVE_REFRESH)來撤消增加或修改模式,並恢復在增加或修改模式之前的當前記錄。其中,參數AFX_MOVE_REFRESH的值為零。

  6.數據庫連接的復用

  在CRecordSet類中定義了一個成員變量m_pDatabase:

  CDatabase* m_pDatabase;


  它是指向對象數據庫類的指針。如果在CRecordSet類對象調用Open()函數之前,將一個已經打開的CDatabase類對象指針傳給m_pDatabase,就能共享相同的CDatabase類對象。如:

  CDatabase m_db;
  CRecordSet m_set1,m_set2;
  m_db.Open(_T(″Super_ES″)); //建立ODBC連接
  m_set1.m_pDatabase=&m_db;
  //m_set1復用m_db對象
  m_set2.m_pDatabse=&m_db;
  // m_set2復用m_db對象


  7.SQL語句的直接執行

  雖然我們可以通過CRecordSet類完成大多數的查詢操作,而且在CRecordSet::Open()函數中也可以提供SQL語句,但是有時候我們還是希望進行一些其他操作,例如建立新表、刪除表、建立新的字段等,這時就需要使用CDatabase類直接執行SQL語句的機制。通過調用CDatabase::ExecuteSQL()函數來完成SQL語句的直接執行:

  BOOL CDB::ExecuteSQLAndReportFailure(const CString& strSQL)
  {TRY
  {m_pdb->ExecuteSQL(strSQL);
  //直接執行SQL語句}
  CATCH (CDBException,e)
  {CString strMsg;
  strMsg.LoadString(IDS_EXECUTE_SQL_FAILED);
  strMsg+=strSQL;
  return FALSE;}
  END_CATCH
  return TRUE;}


  應當指出的是,由於不同的DBMS提供的數據操作語句不盡相同,直接執行SQL語句可能會破壞軟件的DBMS無關性,因此在應用中應當慎用此類操作。

  8.動態連接表

  表的動態連接可以利用在調用CRecordSet::Open()函數時指定SQL語句來實現。同一個記錄集對象只能訪問具有相同結構的表,否則查詢結果將無法與變量相對應。

void CDB::ChangeTable()
{
 if (m_pSet->IsOpen()) m_pSet->Close();
 switch (m_id)
 {
  case 0:
   m_pSet->Open(AFX_DB_USE_DEFAULT_TYPE,″SELECT * FROM SLOT0″);
   //連接表SLOT0
   m_id=1;
   break;
  case 1:
   m_pSet->Open(AFX_DB_USE_DEFAULT_TYPE,″SELECT FROM SLOT1″); //連接表SLOT1
   m_id=0;
   break;
 }
}


  9.動態連接數據庫

  可以通過賦與CRecordSet類對象參數m_pDatabase來連接不同數據庫的CDatabase對象指針,從而實現動態連接數據庫。

void CDB::ChangeConnect()
{
 CDatabase* pdb=m_pSet->m_pDatabase;
 pdb->Close();
 switch (m_id)
 {
  case 0:
   if (!pdb->Open(_T(″Super_ES″)))
    //連接數據源Super_ES
   {
    AfxMessageBox(″數據源Super_ES打開失敗″,″請檢查相應的ODBC連接″, MB_OK|MB_ICONWARNING);
    exit(0);
   }
   m_id=1;
   break;
  case 1:
   if (!pdb->Open(_T(″Motor″)))
   //連接數據源Motor
   {
    AfxMessageBox(″數據源Motor打開失敗″,″請檢查相應的ODBC連接″, MB_OK|MB_ICONWARNING);
    exit(0);
   }
   m_id=0;
   break;
 }
}


  總結:

  Visual C++中的ODBC類庫可以幫助程序員完成絕大多數的數據庫操作。利用ODBC技術使得程序員從具體的DBMS中解脫出來,從而可以減少軟件開發的工作量,縮短開發周期,並提高效率和軟件的可靠性。


免責聲明!

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



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