且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

VIsual C++ ODBC初探

更新时间:2022-09-13 20:38:47

ODBC 是一个调用级接口,它使得应用程序得以访问任何具有 ODBC 驱动程序的数据库中的数据。使用 ODBC 可以创建具有访问任何数据库(最终用户具有该数据库的 ODBC 驱动程序)的权限的数据库应用程序。ODBC 提供了使您的应用程序独立于源数据库管理系统 (DBMS) 的 API。

ODBC 是 Microsoft Windows 开放式服务体系结构 (WOSA) 中的数据库部分。WOSA 是一种接口,允许基于 Windows 的桌面应用程序连接到多种计算环境,而不用为每个平台重写应用程序。

下面是 ODBC 的组件:

  • ODBC API

    函数调用库、错误代码集和用于访问 DBMS 上数据的标准结构化查询语言的 (SQL) 语法。

  • ODBC 驱动程序管理器

    代表应用程序加载 ODBC 数据库驱动程序的动态链接库 (Odbc32.dll)。该 DLL 对您的应用程序是透明的。

  • ODBC 数据库驱动程序

    处理特定 DBMS 的 ODBC 函数调用的一个或多个 DLL。

  • ODBC 游标库

    驻留在 ODBC 驱动程序管理器和该驱动程序之间并处理数据滚动的动态链接库 (Odbccr32.dll)。

  • ODBC 管理器  odbcad32.exe

    用于配置 DBMS 使之可用作应用程序的数据源的工具。

应用程序通过专为 DBMS 编写的 ODBC 驱动程序而不是直接使用 DBMS 的工作方式独立于 DBMS。驱动程序将这些调用转换成 DBMS 可使用的命令,因而简化了开发人员的工作,使得广泛的数据源都可以使用它。

数据库类支持具有 ODBC 驱动程序的任何数据源。例如,这可能包括关系数据库、索引顺序访问方法 (ISAM) 数据库、Microsoft Excel 电子表格或文本文件。ODBC 驱动程序管理到数据源的连接,SQL 用于从数据库中选择记录。

开放式数据库连接 (ODBC) 技术为访问不同种类的 SQL 数据库提供了通用接口。ODBC 是基于结构查询语言 (SQL) 的,以此作为访问数据的标准。此接口提供了最大的互操作性:一个应用程序可以通过一组公用代码访问不同的 SQL 数据库管理系统 (DBMS)。这使得开发人员能够在不以特定的 DBMS 为目标的情况下构建和分发一个客户端/服务器应用程序。然后,会添加数据库驱动程序以将应用程序链接到用户选择的 DBMS。

以下特性说明了 ODBC 的灵活性:

•应用程序没有绑定到专有供应商 API。

•SQL 语句可以明确地包括在源代码中也可以在运行时即时构建。

•应用程序可以忽略基础数据通信协议。

•数据可以用方便于应用程序的格式进行发送和接收。

•ODBC 是随新兴的国际 ISO Call-Level Interface 标准一起设计的。

•目前提供了可用于 55 种最流行的数据库的 ODBC 数据库驱动程序。

 

Visual C++ 的大多数ODBC访问是通过MFC来完成的。

Visual C++的MFC类库定义了几个数据库类,在利用MFC编程时常常用到,它们是CDatabase(数据库类)、CRecordSet(记录集类)、和CRecordView(可视记录集类)。
对于MFC ODBC数据库类来说,CDatabase类对象表示一个同数据源的连接,通过它可以对数据源进行操作。而CRecordSet对象代表从数据源中选择的一组记录的集合,也就是通常所说的记录集对象。
CRecordSet对象通常用于两种形式:动态集(dynasets)和快照集(snapshots)。动态集能与其他用户所做的更改保持同步,快照集则是数据的一个静态视图。每一种形式在记录被打开时都提供一组记录,区别在于,当用户在一个动态集里滚动到一条记录时,有其他用户或是应用程序中的其他记录集所做的更改就会相应地显示出来。CRecordView类对象能以控制的形式显示数据库记录。这个视图是直接连接到一个CRecordSet对象的表视图。

可以使用MFC的模板类来添加数据库的支持,如下图:

VIsual C++ ODBC初探

在CRecordSet类中实现了数据源与记录集之间的数据传输(RFX)

void CdatatestSet::DoFieldExchange(CFieldExchange* pFX)
{
	pFX->SetFieldType(CFieldExchange::outputColumn);
// Macros such as RFX_Text() and RFX_Int() are dependent on the
// type of the member variable, not the type of the field in the database.
// ODBC will try to automatically convert the column value to the requested type
	RFX_Long(pFX, _T("[学号]"), m_stunum);
	RFX_Text(pFX, _T("[姓名]"), m_name );
	RFX_Text(pFX, _T("[性别]"), m_gender);
	RFX_Long(pFX, _T("[年龄]"), m_age);
	RFX_Long(pFX, _T("[班级编号]"), m_classnum);
}

而在View类中的DoDataExchange中实现了控件和数据库字段的连接:

void CdatatestView::DoDataExchange(CDataExchange* pDX)
{
	CRecordView::DoDataExchange(pDX);
	// 可以在此处插入DDX_Field* 函数以将控件“连接”到数据库字段,例如
	// DDX_FieldText(pDX, IDC_MYEDITBOX, m_pSet->m_szColumn1, m_pSet);
	// DDX_FieldCheck(pDX, IDC_MYCHECKBOX, m_pSet->m_bColumn2, m_pSet);
	// 有关更多信息,请参阅MSDN 和ODBC 示例
	DDX_FieldText(pDX,IDC_EDIT1,m_pSet->m_stunum,m_pSet);
	DDX_FieldText(pDX,IDC_EDIT2,m_pSet->m_name,m_pSet);
	DDX_FieldText(pDX,IDC_EDIT3,m_pSet->m_gender,m_pSet);
	DDX_FieldText(pDX,IDC_EDIT4,m_pSet->m_age,m_pSet);
	DDX_FieldText(pDX,IDC_EDIT5,m_pSet->m_classnum,m_pSet);
}

添加记录的实现

void CdatatestView::OnAddData()
{
	UpdateData(TRUE);
	// 检查是否可添加
	if(!m_pSet->IsOpen()| !m_pSet->CanAppend())
	{
		return;
	}

	m_pSet->SetFieldNull(NULL);//清空所有字段
	m_pSet->AddNew();	//设置记录为添加模式

	// 设置记录新值 这儿本应该弹出新的对话框来设置新的记录 但这里直接添加给定的记录
	m_pSet->m_stunum=20060003;
	m_pSet->m_name=L"张三";
	m_pSet->m_gender=L"";
	m_pSet->m_classnum=3;
	m_pSet->m_age=10;

	//提交更新
	if(!m_pSet->Update())
	{
		AfxMessageBox(L"Error:记录添加失败");
	}

	//重建记录集
	m_pSet->Requery();
	m_pSet->MoveLast();
	UpdateData(FALSE);
}

修改记录的简单实现

void CdatatestView::OnEditData()
{
	// 检查是否可更新
	if(m_pSet->CanUpdate())
	{
		m_pSet->Edit();//设置记录为编辑状态
		if(!UpdateData())
			return;
		m_pSet->m_stunum=20070001;
		m_pSet->Update();
		UpdateData(FALSE);
	}
}

删除记录的简单实现

void CdatatestView::Ondelete()
{	
	// 检查是否可更新
	if(m_pSet->CanUpdate())
	{
		m_pSet->Delete();	// 标记为删除
		m_pSet->Requery();	// 重建记录集
		m_pSet->MoveLast();	// 移动到最后一条记录
		UpdateData(FALSE);	// 更新显示
	}
}

数据查询

查询记录使用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()函数,例如:
m_Set.Open(AFX_DATABASE_USE_DEFAULT,strSQL);
如果没有指定参数,程序则使 用缺省的SQL语句,即对在GetDefaultSQL()函数中指定的SQL语 句进行操作: 
CString CTestRecordSet::GetDefaultSQL()
{return _T("[BasicData],[MainSize]");}
对于GetDefaultSQL()函数返回的表名, 对应的缺省操作是SELECT语句,即:
SELECT * FROM BasicData,MainSize

查询过程中也可以利用CRecordSet的 成员变量m_strFilter和m_strSort来执行条件查询和结果排序。m_strFilter 为过滤字符串,存放着SQL语句中WHERE后的条件串;m_strSort 为排序字符串,存放着SQL语句中ORDERBY后的字符串。 如:
m_Set.m_strFilter="TYPE='电动机'";
m_Set.m_strSort="VOLTAGE";
m_Set.Requery();
对应的SQL语句为:
SELECT * FROM BasicData,MainSize
WHERE TYPE='电动机'
ORDER BY VOLTAGE

参数化记录集

使用参数化记录集可以加快程序的执行速度,并可以实现动态功能。

利用参数化可以更直观,更方便地 完成条件查询任务。使用参数化的步骤如下: 
(1).声明参变量: 
Cstring p1;
Float p2;
(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()来移动光标。


本文转自feisky博客园博客,原文链接:http://www.cnblogs.com/feisky/archive/2009/12/19/1627914.html,如需转载请自行联系原作者