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