论坛: 编程破解 标题: 想学吗? 复制本贴地址    
作者: zch001 [zch001]    论坛用户   登录
用Visual C++开发数据库应用程序

 

1、 概述

1、1 Visual C++开发数据库技术的特点

Visual C++提供了多种多样的数据库访问技术――ODBC API、MFC ODBC、
DAO、OLE DB、ADO等。这些技术各有自己的特点,它们提供了简单、灵活、
访问速度快、可扩展性好的开发技术。


简单性

Visual C++中提供了MFC类库、ATL模板类以及AppWizard、ClassWizard等
一系列的Wizard工具用于帮助用户快速的建立自己的应用程序,大大简化了
应用程序的设计。使用这些技术,可以使开发者编写很少的代码或不需编写
代码就可以开发一个数据库应用程序。


灵活性

Visual C++提供的开发环境可以使开发者根据自己的需要设计应用程序的界
面和功能,而且,Visual C++提供了丰富的类库和方法,可以使开发者根据自
己的应用特点进行选择。


访问速度快

为了解决ODBC开发的数据库应用程序访问数据库的速度慢的问题,Visual C++
提供了新的访问技术――OLE DB和ADO,OLE DB和ADO都是基于COM接口的技术,
使用这种技术可以直接对数据库的驱动程序进行访问,这大大提供了访问速度。

可扩展性

Visual C++提供了OLE技术和ActiveX技术,这种技术可以增强应用程序的能力。
使用OLE技术和ActiveX技术可以使开发者利用Visual C++中提供的各种组件、
控件以及第三方开发者提供的组件来创建自己的程序,从而实现应用程序的组件
化。使用这种技术可以使应用程序具有良好的可扩展性。


访问不同种类数据源

传统的ODBC技术只能访问关系型数据库,在Visual C++中,提供了OLE DB访
问技术,不仅可以访问关系型数据库,还可以访问非关系型数据库。

1、2 Visual C++开发数据库技术

Visual C++提供了多种访问数据库的技术,如下所示:


ODBC(Open DataBase Connectivity)


MFC ODBC(Microsoft Foundation Classes ODBC)


DAO (Data Access Object)


OLE DB(Object Link and Embedding DataBase)


ADO(ActiveX Data Object)

这些技术各有自己的特点,总结如下:


ODBC

ODBC是客户应用程序访问关系数据库时提供的一个统一的接口,对于不同的
数据库,ODBC提供了一套统一的API,使应用程序可以应用所提供的API来访问
任何提供了ODBC驱动程序的数据库。而且,ODBC已经成为一种标准,所以,目
前所有的关系数据库都提供了ODBC驱动程序,这使ODBC的应用非常广泛,基本
上可用于所有的关系数据库。

但由于ODBC只能用于关系数据库,使得利用ODBC很难访问对象数据库及其它非
关系数据库。

由于ODBC是一种底层的访问技术,因些,ODBC API可以使客户应用程序能够从
底层设置和控制数据库,完成一些高层数据库技术无法完成的功能。


MFC ODBC

由于直接使用ODBCAPI编写应用程序要编制大量代码,在Visual C++中提供
了MFC ODBC类,封装了ODBC API,这使得利用MFC来创建ODBC的应用程序非
常简便。


DAO

DAO提供了一种通过程序代码创建和操纵数据库的机制。多个DAO构成一个体系
结构,在这个结构中,各个DAO对象协同工作。MFC DAO是微软提供的用于访问
Microsoft Jet数据库文件(*.mdb)的强有力的数据库开发工具,它通过DAO的
封装,向程序员提供了DAO丰富的操作数据库手段。


OLE DB

OLE DB是Visual C++开发数据库应用中提供的新技术,它基于COM接口。因
此,OLE DB对所有的文件系统包括关系数据库和非关系数据库都提供了统一的
接口。这些特性使得OLE DB技术比传统的数据库访问技术更加优越。

与ODBC技术相似,OLE DB属于数据库访问技术中的底层接口。

直接使用OLE DB来设计数据库应用程序需要大量的代码。在VC中提供了ATL模板,
用于设计OLE DB数据应用程序和数据提供程序。


ADO

ADO技术是基于OLE DB的访问接口,它继承了OLE DB技术的优点,并且,ADO
对OLE DB的接口作了封装,定义了ADO对象,使程序开发得到简化,ADO技术属
于数据库访问的高层接口。

 

2、 使用ODBC API

Microsoft 开放数据库互连(ODBC,Open DataBase Connectivity)是
Microsoft Windows 开放服务体系(WOSA)的一部分,是一个数据库访问的标
准接口。使用这一标准接口,我们可以不关心具体的数据库管理系统(DBMS)
的细节,而只要有相应类型数据库的ODBC驱动程序,就可以实现对数据库的访
问。

ODBC编程接口为我们提供了极大的灵活性,我们可以通过这一个接口访问不同
种类的数据库。而且,通过相应的ODBC驱动程序,我们可以方便地实现不同数据
类型之间的转换。

2.1 ODBC API 概述

ODBC是一个应用广泛的数据库访问应用编程接口(API),使用标准的SQL
(结构化查询语言)作为其数据库访问语言。

2.11体系结构

ODBC的结构是建立在客户机/服务器体系结构之上,它包含如下四个部分:

应用程序(Application ):

应用程序即用户的应用,它负责用户与用户接口之间的交互操作,以及调用
ODBC函数以给出SQL请求并提取结果以及进行错误处理。

ODBC驱动程序管理器(Driver Manager):

ODBC驱动程序管理器为应用程序加载和调用驱动程序,它可以同时管理多个应
用程序和多个驱动程序。它的功能是通过间接调用函数和使用动态链接库
(DLL)来实现的,因此它一般包含在扩展名为”DLL”的文件中。

ODBC驱动程序(Driver)

ODBC 驱动程序执行ODBC函数调用,呈送 SQL 请求给指定的数据源,并将结果
返回给应用程序。驱动程序也负责与任何访问数据源的必要软件层进行交互作
用,这种层包括与底层网络或文件系统接口的软件。

数据源

数据源由数据集和与其相关联的环境组成,包括操作系统、DBMS 和网络(如
果存在的话)。ODBC 通过引入“数据源”的概念解决了网络拓扑结构和主机的
大范围差异问题,这样,用户看到的是数据源的名称而不必关心其它东西。

2.12数据类型

ODBC使用两类数据类型:SQL数据类型和C数据类型。SQL数据类型用于数据源,
C数据类型用于应用程序代码中。

2.13句柄

ODBC API 实现数据库操作的手段是语句,这是一个强有力的手段。ODBC语句
除了能执行SQL语句和完成查询操作之外,还能实现大多数数据库操作。

在ODBC中,使用不同的句柄(HANDLE)来标志环境(ENVIRONMENT)、连接
(CONNECTION)、语句(STATEMENT)、描述器(DESCRIPTOR)等。

句柄就是一个应用程序变量,系统用它来存储关于应用程序的上下文信息和应
用程序所用到的一些对象。它和 Windows 编程中的概念类似,不过ODBC 更加
完善了句柄的作用。

1、 环境句柄是 ODBC 中整个上下文的句柄,使用 ODBC 的每个程序从创建环
境句柄开始,以释放环境句柄结束。所有其它的句柄(这一应用程序所有的联
接句柄和语句句柄)都由环境句柄中的上下文来管理。环境句柄在每个应用程
序中只能创建一个。

2、联接句柄管理有关联接的所有信息。联接句柄可以分配多个,这不仅合法而
且很有用;但不要生成不必要的句柄以免资源的浪费。但是,不同的驱动程序支
持的联接情况有所不同,有的驱动程序在一个应用程序中仅支持一个联接句柄,
有的驱动程序仅支持一个语句句柄。在应用程序中,可以在任何适当的时候联接
或脱离数据源,但不要轻易地建立或脱离联接。

3、语句句柄是 ODBC API 真正发挥重要作用的,它被用来处理 SQL 语句及目
录函数,每个语句句柄只与一个联接有关。当驱动程序接收一个来自应用程序
的函数调用指令而该指令包含一个语句句柄时,驱动程序管理器将使用存储在
语句句柄中的联接句柄来将这一函数调用发送给合适的驱动程序。


4、描述器句柄是元数据的集合,这些元数据描述了SQL语句的参数、记录集的
列等信息。当有语句被分配内存之后,描述器自动生成,称为自动分配描述器。
在程序中,应用程序也可调用SQLAllocHandle分配描述器。

当应用程序调用API函数SQLAllocHandle时,驱动管理器或者ODBC驱动程序将
为所声明的句柄类型分配内部结构,返回句柄值。

2.14异常处理

为了在程序开发过程中调试程序,发现程序错误,ODBC API通过两种方式返回
有关ODBC API函数执行的的信息:返回码和诊断记录。返回码返回函数执行的
返回值,说明函数执行成功与否。诊断记录说明函数执行的详细信息。


返回码(Return Code)

每一个ODBC API函数都返回一个代码――返回码,指示函数执行的成功与否。
如果函数调用成功,返回码为SQL_SUCCESS或SQL_SUCCESS_WITH_INFO。
SQL_SUCCESS指示可通过诊断记录获取有关操作的详细信息,
SQL_SUCCESS_WITH_INFO指示应用程序执行结果带有警告信息,可通过诊断记
录获取详细的信息。如果函数调用失败,返回码为SQL_ERROR。

下面的一段代码根据函数SQLFetch()执行的返回码,判断函数执行的成功与否,
从而据此进行相应的处理。

SQLRETURN rtcode;

SQLHSTMT hstmt;

While(rtcode=SQLFetch(hstmt)!=SQL_NO_DATA)

{

if(rtcode==SQL_SUCCESS_WITH_INFO)

{

//显示警告信息

}

else

{

//显示出错信息

break;

}

//函数调用成功,进行处理

}

如果程序执行错误,返回码为SQL_INVALID_HANDLE,程序无法执行,而其它的
返回码都带有程序执行的信息。


诊断记录(Diagnostic Records)

每个ODBC API函数都能够产生一系列的反映操作信息的诊断记录。这些诊断记
录放在相关连的ODBC句柄中,直到下一个使用同一个句柄的函数调用,该诊断
记录一直存在。诊断记录的大小没有限制。

诊断记录有两类:头记录(Head Record)和状态记录(Status Record)。
头记录是第一版权法记录(Record 0),后面的记录为状态记录。诊断记录有
许多的域组成,这些域在头记录和状态记录中是不同的。

可以用SQLGetDiagField函数获取诊断记录中的特定的域,另外,可以使用
SQLGetDiagRec()获取诊断记录中一些常用的域,如SQLSTATE、原始错误号等。

头记录

头记录的各个域中包含了一个函数执行的通用信息,无论函数执行成功与否,
只要不返回SQL_INVALID_HANDLE,都会生成头记录。


状态记录

状态记录中的每个域包含了驱动管理器、ODBC驱动程序或数据源返回的特定的错
误或警告信息,包括SQLSTATE、原始错误码、诊断信息、列号和行号等。只有
函数执行返回SQL_ERROR,SQL_STILL_EXEUTING、SQL_SUCCESS_WITH_INFO、
SQL_NEED_DATA或SQL_NO_DATA时,才会生成诊断记录。


使用SQLGetDiagRec和SQLGetDiagField

应用程序可以调用函数SQLGetDiagRec或SQLGetDiagField获取诊断信息。对于
给定的句柄,这两个函数返回最近使用该句柄的函数的诊断信息。当有使用该
句柄的函数执行时,句柄记录所记录的原有的诊断信息被覆盖。如果函数执行
后产生多个状态记录,程序必须多次调用这两个函数以获取信息。

2.2 应用ODBC API建立应用程序

虽然直接应用ODBC API编制应用程序相对来说较为繁琐,但是,由于直接使
用ODBC API编写的程序相对要简洁、高效。所以,我们有必要学习直接使用
ODBC API编程。

一般地,编写ODBC程序主要有以下几个步骤:


分配ODBC环境


分配连接句柄


连接数据源


构造和执行SQL语句


取得执行结果


断开同数据源的连接


释放ODBC环境

2.21 分配ODBC环境

对于任何ODBC应用程序来说,第一步的工作是装载驱动程序管理器,然后初始
化ODBC环境,分配环境句柄。

首先,程序中声明一个SQLHENV类型的变量,然后调用函数SQLAllocHandle,向
其中传递分配的上述SQLHENV类型的变量地址和SQL_HANDLE_ENV选项。如下代码
所示:

SQLHENV henv;

SQLAllocHandle(SQL_HANDLE_ENV,SQL_NULL_HANDLE,&henv);

执行该调用语句后,驱动程序分配一个结构,该结构中存放环境信息,然后返
回对应于该环境的环境句柄。

2.22分配连接句柄

分配环境句柄后,在建立至数据源的连接之前,我们必须分配一个连接句柄,
每一个到数据源的连接对应于一个连接句柄。

首先,程序定义了一个SQLHDBC类型的变量,用于存放连接句柄,然后调用
SQLAllocHandle函数分配句柄。如下代码所示:

SQLHDBC hdbc;

SQLAllocHandle(SQL_HANDLE_DBC,henv,&hdbc);

henv为环境句柄。

2.23 连接数据源

当连接句柄分配完成后,我们可以设置连接属性,所有的连接属性都有缺省
值,但是我们可以通过调用函数SQLSetConnectAttr()来设置连接属性。用函
数SQLGetConnectAttr()获取这些连接属性。

函数格式如下:

SQLRETURN SQLSetConnectAttr(SQLHDBC ConnectionHandle,SQLINTEGER Attribute,SQLPOINTER ValuePtr,SQLINTEGER StringLength);

SQLRETURN SQLGetConnectAttr(SQLHDBC ConnectionHandle,SQLINTEGER Attribute,SQLPOINTER ValuePtr,SQLINTEGER StringLength);

应用程序可以根据自己的需要设置不同的连接属性。

完成对连接属性的设置之后,就可以建立到数据源的连接了。对于不同的程序和
用户接口,可以用不同的函数建立连接:SQLConnect、SQLDriverConnect、SQLBrowseConnect。

SQLConnect

该函数提供了最为直接的程序控制方式,我们只要提供数据源名称、用户ID和
口令,就可以进行连接了。

函数格式:

SQLRETURN SQLConnect(SQLHDBC ConnectionHandle,SQLCHAR ServerName,SQLSMALLINT NameLength1,SQLCHAR UserName,SQLSMALLINT NameLength2,SQLCHAR *Authentication,SQLSMALLINT NameLength3);

参数:

ConnectionHandle 连接句柄

ServerName 数据源名称

NameLength1 数据源名称长度

UserName 用户ID

NameLength2 用户ID长度

Authentication 用户口令

NameLength3 用户口令长度

返回值:

SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.

成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,
可以用函数SQLGetDiagRec获取相应SQLSTATE的值。

 

下面的代码演示了如何使用ODBC API的SQLConnect函数建立同数据源SQLServer
的连接。

 

#include “sqlext.h”

SQLHENV henv;;

SQLHDBC hdbc;

SQLHSTMT hstmt;

SQLRETURN retcode;

/*Allocate environment handle */

retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv); 

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set the ODBC version environment attribute */

retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0); 

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Allocate connection handle */

retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc); 

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set login timeout to 5 seconds. */

SQLSetConnectAttr(hdbc, (void*)SQL_LOGIN_TIMEOUT, 5, 0);

/* Connect to data source */

retcode = SQLConnect(hdbc, (SQLCHAR*) "Sales", SQL_NTS,

(SQLCHAR*) "JohnS", SQL_NTS,

(SQLCHAR*) "Sesame", SQL_NTS);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO){

/* Allocate statement handle */

retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); 

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Process data */;

SQLFreeHandle(SQL_HANDLE_STMT, hstmt);

}

SQLDisconnect(hdbc);

}

SQLFreeHandle(SQL_HANDLE_DBC, hdbc); 



}

SQLFreeHandle(SQL_HANDLE_ENV, henv);

SQLDriveConnect

函数SQLDriveConnect用一个连接字符串建立至数据源的连接。它可以提供比
SQLConnect函数的三个参数更多的信息,可以让用户输入必要的连接信息。

如果连接建立,该函数返回完整的字符串,应用程序可使用该连接字符串建立另
外的连接。

函数格式:

SQLRETURN SQLDriverConnect(SQLHDBC ConnectionHandle,SQLHWND WindowHandle,SQLCHAR InConnectionString,SQLSMALLINT StringLength1,SQLCHAR OutConnetionString,SQLSMALLINT BufferLength,SQLSMALLINT *StringLength2Ptr,SQLSMALLINT DriverCompletion);

参数:

ConnectionHandle 连接句柄

WindowHandle 窗口句柄,应用程序可以用父窗口的句柄,或用NULL指针

InConnectionString 连接字符串长度

OutConnectionString 一个指向连接字符中的指针

BufferLength 存放连接字符串的缓冲区的长度

StringLength2Ptr 返回的连接字符串中的字符数

DriverCompletion 额外连接信息,可能取值有:SQL_DRIVER_PROMPT,

SQL_DRIVER_COMPLETE, 

SQL_DRIVER_COMPLETE_REQUIRED, or

SQL_DRIVER_NOPROMPT.

返回值:

SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.

成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可
以用函数SQLGetDiagRec获取相应SQLSTATE的值。

 

SQLBrowseConnect

函数SQLBrowseConnect支持以一种迭代的方式获取到数据源的连接,直到最后
建立连接。它是基于客房机/服务器的体系结构,因此,本地数据库不支持该函
数。

一般,我们提供部分连接信息,如果足以建立到数据源的连接,则成功建立连
接,否则返回SQL__NEED__DATA,并在OutConnectionString参数中返回所需要的
信息。

函数格式:

SQLRETURN SQLBrowseConnect(SQLHDBC ConnectionHandle,SQLCHAR* InConnectionString,SQLSAMLLINT StringLength1,SQLCHAR* OutConnectionString,SQLSMALLINT BufferLength,SQLSMALLINT *StringLength2Ptr);

参数:

ConnectionHandle 连接句柄

InConnectionString 指向输出字符串的指针

StringLength1 输出字符串的指针长度

OutConnectionString 指向输出字符串的指针

BufferLength 用于存放输出字符串的缓冲区的长度

StringLength2Ptr 实际返回的字符串的长度

 

返回值:

SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.

成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可
以用函数SQLGetDiagRec获取相应SQLSTATE的值。

 

下面的代码讲述了如何使用ODBC API的SQLBrowseConnect函数建立同数据源的
连接。

 

#define BRWS_LEN 100SQLHENV 

henv;SQLHDBC hdbc;

SQLHSTMT hstmt;

SQLRETURN retcode;

SQLCHAR szConnStrIn[BRWS_LEN], szConnStrOut[BRWS_LEN];

SQLSMALLINT cbConnStrOut;/* Allocate the environment handle. */

retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv); 

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set the version environment attribute. */

retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, SQL_OV_ODBC3, 0);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Allocate the connection handle. */

retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Call SQLBrowseConnect until it returns a value other than */

/* SQL_NEED_DATA (pass the data source name the first time). */

/* If SQL_NEED_DATA is returned, call GetUserInput (not */

/* shown) to build a dialog from the values in szConnStrOut. */

/* The user-supplied values are returned in szConnStrIn, */

/* which is passed in the next call to SQLBrowseConnect. */

lstrcpy(szConnStrIn, "DSN=Sales"); do {

retcode = SQLBrowseConnect(hdbc, szConnStrIn, SQL_NTS,

szConnStrOut, BRWS_LEN, &cbConnStrOut);

if (retcode == SQL_NEED_DATA)

GetUserInput(szConnStrOut, szConnStrIn);

} while (retcode == SQL_NEED_DATA);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO){

/* Allocate the statement handle. */

retcod 



地主 发表时间: 11/22 21:16

回复: long_hair [long_hair]   论坛用户   登录
同上

B1层 发表时间: 11/23 02:14

回复: guixing [guixing]   论坛用户   登录
我说老兄 你还不如举个简单的编程例子呢  这样我都晕了  看不懂了

B2层 发表时间: 11/23 21:16

回复: sina [sina]   论坛用户   登录
你好呀,我是新来得

B3层 发表时间: 11/28 15:13

回复: niuges [niuges]   论坛用户   登录
它和JAVA的JDBC技术相比哪一个更好一点呢?

B4层 发表时间: 11/28 20:21

回复: napolun [napolun]   版主   登录
不错

B5层 发表时间: 11/28 22:35

回复: lih [lih]   论坛用户   登录
我保存下来先!

B6层 发表时间: 12/08 20:08

论坛: 编程破解

20CN网络安全小组版权所有
Copyright © 2000-2010 20CN Security Group. All Rights Reserved.
论坛程序编写:NetDemon

粤ICP备05087286号