ODBC基本概念
ODBC(Open
一個基於ODBC的應用程序對數據庫的操作不依賴任何DBMS,不直接與DBMS打交道,所有的數據庫操作由對應的DBMS的ODBC驅動程序完成。也就是說,不論是FoxPro、Access還是Oracle數據庫,均可用ODBC
一個完整的ODBC由下列幾個部件組成:
應用程序(Application)。
ODBC管理器(Administrator)。該程序位於Windows
驅動程序管理器(Driver
ODBC
ODBC
數據源。數據源包含了數據庫位置和數據庫類型等信息,實際上是一種數據連接的抽象。
各部件之間的關系如圖下圖所示:
應用程序要訪問一個數據庫,首先必須用ODBC管理器注冊一個數據源,管理器根據數據源提供的數據庫位置、數據庫類型及ODBC驅動程序等信息,建立起ODBC與具體數據庫的聯系。這樣,只要應用程序將數據源名提供給ODBC,ODBC就能建立起與相應數據庫的連接。
在ODBC中,ODBC
在訪問ODBC數據源時需要ODBC驅動程序的支持。用Visual
ADO對象訪問模型
本節簡要介紹了微軟的活動數據對象(ADO)模型,結合實例闡述了在Visual
關鍵詞:
1
活動數據對象(ADO)是一組由微軟提供的COM組件。
2
與微軟的其它數據訪問模型DAO和RDO相比,ADO對象模型非常精煉,僅由三個主要對象Connection、Command、Recordset和幾個輔助對象組成,其相互關系如圖所示。Connection對象提供OLE
3
(1)由於封裝了許多底層工作,使用ADO與使用ODBC幾乎是一樣方便。
(2)
(3)在定義ADO記錄集變量和數據庫表字段綁定類時,要求記錄集的字段變量、狀態變量與數據庫表字段的個數、順序必須相同。這一點比在FMC中使用ODBC要復雜一些。但在數據庫字段與ADO記錄集字段變量綁定的宏中,ADO
(4)ADO允許同一Connection實例下有多個Record
(5)ADO允許進行批更新(使用的Update
4
利用微軟在Micrsoft
以下給出一個Visual
(1)
例:#import
(2)
例:
class
{
public:
DBTIMESTAMP
long
long
long
WORD
WORD
WORD
WORD
BEGIN_ADO_BINDING(CIntlive)
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)
(4)
例:
_ConnectionPtr
_RecordsetPtr
(5)
例:
CIntlive
IADORecordBinding
(6)
例:
pConnection1.CreateInstance(_uuidof(Connection));
rstADO1.CreateInstance(__uuidof(Recordset))
(7)
例:
PConnection1->Open("driver={SQL
rstADO1->Open("data",
adOpenKeyset,adLockBatchOptimistic,
(8)
例:
RstADOBind1->BindToRecordset(&m_intdata);
(9)
rstADO1->Move
rstADO1->Update(_variant_t("quality"),_variant_t("3")));
rstADO1->Update
(10)
例:
RstADO1->Close();
RstADOBind2->Release();
(11)
(12)
5
作為ODBC的替代產品,ADO確實有其過人之處。由於ADO數據源幾乎覆蓋了目前常見的數據源類型,對於ODBC所不支持的數據源,ADO無疑是唯一的選擇。而ADO的批更新功能,更是網絡環境下大數據量更新應用的重要因素。由於ADO缺乏大量的第三方廠商的支持,使得ADO目前遠不如ODBC普及,但其面向對象的特性將使ADO具有比較廣闊的發展前景。
ODBC編程實例
Microsoft
用戶使用自己的DBMS數據庫管理功能生成新的數據庫模式后,就可以使用ODBC來登錄數據源。對用戶的應用程序來說,只要安裝有驅動程序,就能注冊很多不同的數據庫。登錄數據庫的具體操作參見有關ODBC的聯機幫助。
一、MFC提供的ODBC數據庫類
Visual
CDatabase類對象提供了對數據源的連接,通過它可以對數據源進行操作。
CRecordSet類對象提供了從數據源中提取出的記錄集。CRecordSet對象通常用於兩種形式:動態行集(dynasets)和快照集(snapshots)。動態行集能與其他用戶所做的更改保持同步,快照集則是數據的一個靜態視圖。每種形式在記錄集被打開時都提供一組記錄,所不同的是,當在一個動態行集里滾動到一條記錄時,由其他用戶或應用程序中的其他記錄集對該記錄所做的更改會相應地顯示出來。
CRecordView類對象能以控件的形式顯示數據庫記錄,這個視圖是直接連到一個CRecordSet對象的表視圖。
二、應用ODBC編程
應用Visual
當AppWizard詢問是否包含數據庫支持時,如果想讀寫數據庫,那么選定Database
選好數據庫支持之后,Database
特別需要指出的是:在生成的應用程序框架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
{return
對於GetDefaultSQL()函數返回的表名,對應的缺省操作是SELECT語句,即:
SELECT
在查詢過程中,也可以利用CRecordSet的成員變量m_strFilter和m_strSort來執行條件查詢和結果排序。m_strFilter為過濾字符串,存放着SQL語句中WHERE后的條件串;m_strSort為排序字符串,存放着SQL語句中ORDER
Super_ESSet.m_strFilter=″TYPE=‘電動機’″;
Super_ESSet.m_strSort=″VOLTAGE″;
Super_ESSet.Requery();
對應的SQL語句為:
SELECT
WHERE
ORDER
除了直接賦值給m_strFilter以外,還可以使用參數化。利用參數化可以更直觀、更方便地完成條件查詢任務。使用參數化的步驟如下:
S聲明參變量:
CString
float
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=?
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),
m_pSet->m_type=″電動機″;
……
//輸入新的字段值
m_pSet->Update();
//將新記錄存入數據庫
m_pSet->Requery();
//重建記錄集
3.刪除記錄
可以直接使用Delete()函數來刪除記錄,並且在調用Delete()函數之后不需調用Update()函數:
m_pSet->Delete();
if
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*
它是指向對象數據庫類的指針。如果在CRecordSet類對象調用Open()函數之前,將一個已經打開的CDatabase類對象指針傳給m_pDatabase,就能共享相同的CDatabase類對象。如:
CDatabase
CRecordSet
m_db.Open(_T(″Super_ES″));
m_set1.m_pDatabase=&m_db;
//m_set1復用m_db對象
m_set2.m_pDatabse=&m_db;
//
7.SQL語句的直接執行
雖然我們可以通過CRecordSet類完成大多數的查詢操作,而且在CRecordSet::Open()函數中也可以提供SQL語句,但是有時候我們還是希望進行一些其他操作,例如建立新表、刪除表、建立新的字段等,這時就需要使用CDatabase類直接執行SQL語句的機制。通過調用CDatabase::ExecuteSQL()函數來完成SQL語句的直接執行:
BOOL
{TRY
{m_pdb->ExecuteSQL(strSQL);
//直接執行SQL語句}
CATCH
{CString
strMsg.LoadString(IDS_EXECUTE_SQL_FAILED);
strMsg+=strSQL;
return
END_CATCH
return
應當指出的是,由於不同的DBMS提供的數據操作語句不盡相同,直接執行SQL語句可能會破壞軟件的DBMS無關性,因此在應用中應當慎用此類操作。
8.動態連接表
表的動態連接可以利用在調用CRecordSet::Open()函數時指定SQL語句來實現。同一個記錄集對象只能訪問具有相同結構的表,否則查詢結果將無法與變量相對應。
void
{
if
switch
{
case
m_pSet->Open(AFX_DB_USE_DEFAULT_TYPE,″SELECT
//連接表SLOT0
m_id=1;
break;
case
m_pSet->Open(AFX_DB_USE_DEFAULT_TYPE,″SELECT
m_id=0;
break;
}
}
9.動態連接數據庫
可以通過賦與CRecordSet類對象參數m_pDatabase來連接不同數據庫的CDatabase對象指針,從而實現動態連接數據庫。
void
{
CDatabase*
pdb->Close();
switch
{
case
if
//連接數據源Super_ES
{
AfxMessageBox(″數據源Super_ES打開失敗″,″請檢查相應的ODBC連接″,
exit(0);
}
m_id=1;
break;
case
if
//連接數據源Motor
{
AfxMessageBox(″數據源Motor打開失敗″,″請檢查相應的ODBC連接″,
exit(0);
}
m_id=0;
break;
}
}
總結:
Visual