Visual C++ 提供提供了多种数据库访问技术,其中最主要的是开放式数据库连接(Open Database Connectivity, ODBC)和数据存取对象(Data Access Object, DAO)两种数据库访问技术。
ODBC是技术上成熟的可靠标准接口,这里介绍它的使用。
1. ODBC概述
ODBC建立了一组数据库访问规范,为用户提供简单、标准、透明和统一的数据库访问的编程接口(API),使应用程序独立于DBMS(数据库管理系统)。ODBC API作为数据库的一种底层访问技术,支持SQL语言,并且用户可以直接将SQL语句提交给ODBC。
ODBC体系的4大组件:
(1) 应用程序:执行处理并调用ODBC API函数,提交SQL语句并获取结果
(2) 驱动程序管理器(driver manager):根据应用程序的需要加载或卸载驱动程序,处理ODBC API函数调用,或将函数调用转交给ODBC驱动程序。包括一组ODBC API函数,它们位于ODBC32.dll动态连接库中
(3) ODBC驱动程序(driver):处理ODBC API函数调用,提交SQL请求到一个指定的数据源,并把结果返回给应用程序。ODBC驱动程序通常是一个DLL文件。
(4) 数据源(data source):应用程序要连接一个数据库,首先必须设置一个数据源。一个数据源包含了用户要访问的数据库以及相关的DBMS、网络平台等信息。
ODBC技术对数据库的操作不依赖于具体的DBMS,不直接与DBMS打交道,所有的数据库操作由对应的DBMS的ODBC驱动程序完成。
但注意ODBC API并不能直接访问数据库。驱动程序管理器负责将应用程序对ODBC API的调用传递给对应的ODBC驱动程序,由驱动程序完成相应的操作(安全性考虑)。
2. MFC ODBC数据库类
MFC的ODBC类对复杂的ODBC API进行了封装,提供了简化的调用接口,从而方便了开发使用。如果要对数据库底层操作,也可以直接调用ODBC API。
MFC的ODBC数据库类主要包括:
(1)CDatabase:建立与数据源的连接
(2)CRecordSet:从数据源中提取的记录集。CRecordSet类对象有动态行集和快照集两种形式,每一种在记录集被打开时都提供一组记录。动态行集:能保持与其他用户所做的更改同步,快照集:数据的静态视图。
(3)CRecordView:连接到CRecordSet对象的表单视图,CFormView的派生类,用于显示数据库记录。
(4)CFieldExchange:支持记录字段交换
(5)CDBException:用于处理ODBC类产生的异常。
总之,CDatabase针对某个数据库,负责连接数据源;CRecordSet针对数据源中的记录集,负责对记录的操作;CRecordView负责可视化界面;CFieldExchange负责CRecordSet与数据源的数据交换。
3. 编程示例
要使用ODBC对数据库操作,首先利用ODBC数据源管理器配置与数据库相对应的数据源,然后再设计应用程序的实现。
(1)数据库应用程序
CRecordView使用:提供ID_RECORD_FIRST、ID_RECORD_LAST、ID_RECORD_NEXT、ID_RECORD_PREV等命令的支持,用于滚动记录,成员函数OnMove()处理这些命令消息。
BOOL CRecordView::OnMove(UINT nIDMoveCommand)
{
CRecordSet *pSet = OnGetRecordSet();
if(pSet->CanUpdate())
{
pSet->Edit();//进入编辑模式
if(!UpdateData())//将控件中数据更新到记录集对象的域数据成员(field dtaa)中
return TRUE;
pSet->Update();//域数据成员(field dtaa)的值写入数据源
}
switch(nIDMoveCommand)//处理4个不同命令
{
case ID_RECORD_PREV:
pSet->MovePrev();
if(!pSet->IsBOF())
break;
case ID_RECORD_FIRST:
pSet->MoveFirst();
break;
case ID_RECORD_NEXT:
pSet->MoveNext();
if(!pSet->IsEOF())
break;
if(!pSet->CanScroll())//Clear out screen since we're sitting on EOF
{
pSet->SetFieldNull(NULL);
break;
}
case ID_RECORD_LAST:
pSet->MoveLast();
break;
default:
ASSERT(FALSE);
}
// show the result of move operation
UpdateData(FALSE); // 把新的当前记录(move操作之后)的内容直入表单视图的控件内
return TRUE;
}
调用了CRecordSet类的多种用于滚动记录的成员函数,它们在滚动到一个新的纪录时会把该记录传递到域数据成员中。OnMove()函数完成了两次表单控件和数据源的数据交换。
(2)支持删除和添加记录功能
上面是对数据库的浏览功能,除此以外,还有修改功能、添加和删除记录功能。
pSet->AddNew(); // 添加记录
pSet->Delete(); // 删除记录
UpdateData(FALSE); // 更新表单视图
pSet的滚动操作:
pSet->MoveNext();
if(pSet->IsEOF())//滚出了记录集的边界,则滚动到最后一个记录
pSet->MoveLast();
if(pSet->IsBOF())//如果记录变空了,则清除域数据成员
pSet->SetFieldNull(NULL);
UpdateData(FALSE);//更新表单视图
查询
pSet->Query();