华中理工大学电力工程系 董毅 摘要:ODBC(Open Database Connectivity,开放式数据库连接),是一种用来在相关或不相关的数据库管理系统(DBMS)中存取数据的标准应用程序接口(API)。本文给出Windows95环境下用VisualC++进行ODBC编程的具体方法及 技巧。 关键字:ODBC,VisualC++,Windows编程。 一.概述 ----ODBC是一种使用SQL的程序设计接口。使用ODBC让应用程序的编写者避免了与数据源相联的复杂性。这项技术目前已经得到了大多数DBMS厂商们的广泛支持。 ----Microsoft Developer Studio为大多数标准的数据库格式提供了32位ODBC驱动器。这些标准数据格式包括有:SQL Server、Access、Paradox、dBase、FoxPro、Excel、Oracle以及Microsoft Text。如果用户希望使用其他数据格式,用户需要相应的ODBC驱动器及DBMS。 ----用户使用自己的DBMS数据库管理 功能生成新的数据库模式后,就可以使用ODBC来登录数 据源。对用户的应用程序来说,只要安装有驱动程序,就能注册很多不同的数据库。登录数据库的具体操作参见有关ODBC的联机帮助。 二.MFC提供的ODBC数据库类 ----VisualC++的MFC基类库定义了几个数据库类。在利用ODBC编程时,经常要使用到CDatabase(数据库类),CRecordSet(记录集类)和CRecordView(可视记录集类)。 其中: ----CDatabase类对象提供了对数据源的连接,通过它你可以对数据源进行操作。 ----CRecordSet类对象提供了从数据源 中提取出的记录集。CRecordSet对象通常用于两种形式: 动态行集(dynasets)和快照集(snapshots)。动态行集能保 持与其他用户所做的更改保持同步。快照集则是数据的一个静态视图。每一种形式在记录集被打开时都提供一组记录,所不同的是,当你在一个动态行集里滚 动到一条记录时,由其他用户或是你应用程序中的其他记录集对该记录所做的更改会相应地显示出来。 ----CRecordView类对象能以控制的形式 显示数据库记录。这个视图是直接连到一个CRecordSet对象的表视图。 三.应用ODBC编程 ----应用VisualC++的AppWizard可以自动生 成一个ODBC应用程序框架。方法是:打开File菜单的New选 项,选取Projects,填入工程名,选择MFCAppWizard(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建立,目的是在视表单和记录集之间建立联系,使得记录集中的查询结果能够很容易地在视表单上显示出来。有关m_pSet的详细 用法可以参见VisualC++ OnlineBook。 ----程序与数据语言建立联系,使 用CDatebase::OpenEx()或CDatabase::Open()函数来进行初始化。数据库 对象必须在你使用它构造一个记录集对象之前被初始化。 ----下面举例说明在VisualC++环境中ODBC 的编程技巧: ----1.查询记录 ----Super_ESSet.Open(AFX_DATABASE_USE_DEFAULT,strSQL); ----如果没有指定参数,程序则使 用缺省的SQL语句,即对在GetDefaultSQL()函数中指定的SQL语 句进行操作: CString CSuper_ESSet::GetDefaultSQL() {return _T("[BasicData],[MainSize]");} ----对于GetDefaultSQL()函数返回的表名, 对应的缺省操作是SELECT语句,即: ----SELECT * FROM BasicData,MainSize ----查询过程中也可以利用CRecordSet的 成员变量m_strFilter和m_strSort来执行条件查询和结果排序。m_strFilter 为过滤字符串,存放着SQL语句中WHERE后的条件串;m_strSort 为排序字符串,存放着SQL语句中ORDERBY后的字符串。 如: 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以外,还 可以使用参数化。利用参数化可以更直观,更方便地 完成条件查询任务。使用参数化的步骤如下: ----(1).声明参变量: CStringp1; floatp2; ----(2).在构造函数中初始化参变量 p1=_T(""); p2=0.0f; m_nParams=2; ----(3).将参变量与对应列绑定 pFX->SetFieldType(CFieldExchange::param) RFX_Text(pFX,_T("P1"),p1); RFX_Single(pFX,_T("P2"),p2); ----完成以上步骤之后就可以利用 参变量进行条件查询了: m_pSet->m_strFilter="TYPE=?ANDVOLTAGE=?";
m_pSet->p1="电动机";
m_pSet->p2=60.0;
m_pSet->Requery();
----参变量的值按绑定的顺序替换 查询字串中的“?”适配符。 ----如果查询的结果是多条记录的 话,可以用CRecordSet类的函数Move(),MoveNext(),MovePrev(),MoveFirst() 和MoveLast()来移动光标。 ----2.增加记录 m_pSet->AddNew(); //在表的末尾增加新记录 m_pSet->SetFieldNull(&(m_pSet->m_type),FALSE); m_pSet->m_type="电动机"; ... //输入新的字段值 m_pSet-> Update(); //将新记录存入数据库 m_pSet->Requery(); //重建记录集 ----3.删除记录 m_pSet->Delete(); if(!m_pSet->IsEOF()) m_pSet->MoveNext(); else m_pSet->MoveLast(); ----4.修改记录 m_pSet->Edit(); //修改当前记录 m_pSet->m_type="发电机"; //修改当前记录字段值 ... m_pSet->Update(); //将修改结果存入数据库 m_pSet->Requery(); ----5.撤消操作 ----CRecordSet::Move(AFX_MOVE_REFRESH); ----来撤消增加或修改模式,并恢复在增加或修改模式之前的当前记录。其中的参数AFX_MOVE_REFRESH 的值为零。 ----6.数据库连接的复用 ----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语句的直接执行 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.动态连接表 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.动态连接数据库 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; } } 四.总结 ----VisualC++中的ODBC类库可以帮助程 序员完成绝大多数的数据库操作。利用ODBC技术使得程 序员从具体的DBMS中解脱出来,从而极大的减少了软件 开发的工作量,缩短开发周期,提高了效率和软件的 可靠性。本文总结的笔者从事软件开发的一些经验心 得希望对从事ODBC开发的工作者有所帮助。 参考文献
|