第 1 章
第 2 章
2.1
2.1.1
2.1.2
2.1.3
2.1.4
2.2
2.2.1
2.2.2
2.2.3
2.2.4
2.2.5
2.2.6
2.2.7
2.3
2.4
2.4.1
2.5
2.5.1
2.5.2
2.5.3
2.5.4
2.5.5
2.5.6
2.5.7
2.5.8
2.5.9
2.5.10
第 3 章
第 1 章
在文章的开头做一个习惯性的介绍。
本文从2002年11月开始写,基本上在2002年12月时完成,当时本来作为一本书的一个章节,后来由于某些原因没有完成该书。这段时间将本文内容进行了一些整理,放在网上希望能够给大家一些帮助。
本文的内容主要是关于ODBC 的功能,所有内容都与ODBC 3.X版本兼容。
本文简要介绍了ODBC的历史和发展,也介绍了ODBC的基本的常用功能。大致包括:
l
l
l
l
l
l
l
本文的数据库利用了MS SQL Server,ODBC在使用时是与数据库无关的所以所有例程都可以运行在其他数据库上,例如Oracle。其实利用Access数据库来进行练习也是可以的,但是由于Access不能支持存储过程,所以我没有使用Access数据库。
由于例程代码没有找到,所以没有就没有办法提供,但是文中的代码都比较详细而且有具体的解释。
书中有很多错误和不足之处希望大家能够容忍和包含,也欢迎来信指出。
第 2 章
2.1
2.1.1
请允许我将那时候成为第二黑暗时代,第一黑暗时代是没有数据库的时代。
ODBC的出现结束了数据库开发的无标准时代。在没有ODBC以前不同的数据库的开发所采用的标准是不统一的。一般来讲不同的数据库厂商都有自己的数据库开发包,这些开发包支持两种模式的数据库开发:预编译的嵌入模式(例如Oracle的ProC,SQL Server的ESQL)和API调用(例如Oracle的OCI)。
对于一个开发人员来讲使用预编译方式开发是极其痛苦的,我就有过这样的经历,所有的SQL语句要写在程序内部,并且遵守一定的规则,然后由数据库厂商的预编译工具处理后形成C代码,最后由C编译器进行编译。预编译的最大问题就在于无法动态的生成SQL语句,我想作为一个程序员是很难接受的。
接下来的是使用API进行开发,和预编译相比算是前进了一大步。数据库厂商提供了开发包,你通过各种API函数就可以连接数据库,执行查询、修改、删除,操纵光标,执行存储过程等。对于程序员来讲有了更多的自由,而且可以创建自己的开发包。但是这一切的开发只能针对同一种数据库。
Oracle的OCI是一个非常优秀的C语言开发包,在ODBC中就在很多地方参照了OCI的设计。
2.1.2
ODBC(Open Database Connectivity)是由微软公司提出的一个用于访问数据库的统一界面标准,随着客户机/服务器体系结构在各行业领域广泛应用,多种数据库之间的互连访问成为一个突出的问题,而 ODBC成为目前一个强有力的解决方案。ODBC之所以能够操作众多的数据库,是由于当前绝大部分数据库全部或部分地遵从关系数据库概念,ODBC看待这些数据库时正是着眼了这些共同点。虽然支持众多的数据库,但这并不意味ODBC会变得复杂,ODBC是基于结构化查询语言(SQL),使用SQL可大大简化其应用程序设计接口(API),由于ODBC思想上的先进性,而且没有同类标准或产品与之竞争,因而越来越受到众多厂家和用户的青睐。目前,ODBC已经成为客户机/服务器系统中的一个重要支持技术。
在1994年时ODBC有了第一个版本,这种名为Open Data Base Connection(开放式数据库互连)的技术很快通过了标准化并且得到各个数据库厂商的支持。ODBC在当时解决了两个问题,一个是在Windows 平台上的数据库开发,另一个是建立一个统一的标准,只要数据厂商提供的开发包支持这个标准,那么开发人员通过ODBC开发的程序可以在不同的数据库之间自由转换。这对开发人员来说的确值得庆贺。
ODBC参照了X/OpenData Management: SQL Call-Level Interface和ISO/ICE1995 Call-Level Interface标准,在ODBC版本3.X中已经完全实现了这两个标准的所有要求。所以本书所有内容都基于ODBC 3.0以上版本。
最开始时支持ODBC的数据库只有SQL Server,ACCESS,FoxPro,这些都时微软的产品,他们能够支持ODBC一点也不奇怪,但是那时候Windows的图形界面已经成为了客户端软件最理想的载体,所以各大数据厂商也在不久后发布了针对ODBC的驱动程序。
在Windows 3.X和Windows 95的时候ODBC并不作为系统的组成部分出现,使用前必须另行安装。但到了Windows 98的时候,当你安装好操作系统后,ODBC不需要另行安装了,因为它已经成为了操作系统的一部分。这对很多拒绝ODBC的人来说又少了一个借口。
作为一个程序员,至少是我,我实在找不出什么理由不为ODBC欢呼。此外ODBC的结构很简单和清晰,学习和了解ODBC的机制和开发方法对学习ADO等其他的数据库访问技术会有所帮助。
2.1.3
图2.1显示了ODBC的结构。
图2.1
应用程序(Application)
应用程序本身不直接与数据库打交道,主要负责处理并调用ODBC函数,发送对数据库的SQL请求及取得结果。
驱动程序管理器(Driver Manager )
驱动程序管理器是一个带有输入程序的动态链接库(DLL),主要目的是加载驱动程序,处理ODBC调用的初始化调用,提供ODBC调用的参数有效性和序列有效性。
驱动程序(Driver)
驱动程序是一个完成ODBC函数调用并与数据库相互影响的DLL,这些驱动程序可以处理对于特定的数据的数据库访问请求。对于应用驱动程序管理器送来的命令,驱动程序再进行解释形成自己的数据库所能理解的命令。驱动程序将处理所有的数据库访问请求,对于应用程序来讲不需要关注所使用的是本地数据库还上网络数据库。
2.1.4
ODBC 接口的优势之一为互操作性,程序设计员可以在不指定特定数据源情况下创建ODBC应用程序。从应用程序角度方面,为了使每个驱动程序和数据源都支持相同的 ODBC函数调用和SQL语句集,ODBC接口定义了一致性级别,即ODBC API一致性和ODBC SQL语法一致性。SQL一致性规定了对SQL语句语法的要求,而API一致性规定了驱动程序需要实现的ODBC函数。一致性级别通过建立标准功能集来帮助应用程序和驱动程序的开发者,应用程序可以很容易地确定驱动程序是否提供了所需的功能,驱动程序可被开发以支持应用程序选项,而不用考虑每个应用程序的特定请求。
2.2
2.2.1
DSN (Data Source Name)是用于指定ODBC与相关的驱动程序相对应的一个入口,所有DSN的信息由系统进行管理,一般来讲当应用程序要使用ODBC访问数据库时,就需要指定一个DSN以便于连接到一个指定的ODBC驱动程序。在控制面板中打开ODBC管理器,回看到如图2.2的界面。
图2.2
DSN共分为三类:
l
l
l
一个使用Access数据库的DSN中的信息如下:
[ODBC]
DRIVER=Driver do Microsoft Access (*.mdb)
UID=admin
DefaultDir=C:\www.vchelp.net\DB
DBQ=C:\www.vchelp.net\DB\chat.mdb
对于文件DSN来讲这些信息存放在文件中,对于用户DSN和系统DSN来讲这些信息存放在注册表内。你可以通过创建文件DSN来查看每种DSN对应的信息内容。
下面的例子将告诉你如何添加一个SQL Server的DSN。
图2.3
图2.3中的四个步骤分别是:
l
l
l
l
2.2.2
你需要下面的文件:
l
l
l
这些文件在VC6,VC7都已经随开发工具提供了,不需要另外安装。
此外所有的ODBC函数都以SQL开始,例如SQLExecute,SQLAllocHandle。
2.2.3
在ODBC中SQL语句的执行方式分为两种,直接执行和准备执行。
直接执行是指由程序直接提供SQL语句,例如:Select * from test_table并调用SQLExecDirect执行,准备执行是指先提供一个SQL语句并调用SQLPrepare,然后当语句准备好后调用 SQLExecute执行前面准备好的语句。准备执行多用于数据插入和数据删除,在进行准备时将由ODBC驱动程序对语句进行分析,在实际执行时可以避免进行SQL语句分析所花费的时间,所以在进行大批量数据操作时速度会比直接执行有明显改善。在后面的章节中我会详细介绍准备执行与行列绑定与参数替换的用法。
2.2.4
对于SQL查询语句,ODBC会返回一个光标,与光标对应的是一个结果集合(可以理解为一个表格)。开发人员利用光标来浏览所有的结果,你可以利用ODBC API函数移动光标,并且获取当前光标指向的行的列字段的数值。此外还可以通过光标来对光标当前所指向的数据进行修改,而修改会直接反映到数据库中。
对于数据更新语句,如插入,删除和修改,在执行后可以得到当前操作所影响的数据的行数。
2.2.5
图2.4中是一个基本的使用ODBC API的一个流程,你现在并不理解上面所有的函数的作用,这没有关系。但希望能够通过这幅图给你一个最初的映象,那就是使用ODBC API开发并不复杂。
2.2.6
在使用ODBC开发时一个重要的问题就是数据转换的问题,在ODBC中存在下面的几类数据:
l
l
l
在程序运行过程中数据需要经历两次转换:C语言的数据或结构类型与ODBC的数据类型的转换,ODBC与SQL间数据类型的转换。所以ODBC所定义的数据类型起到了中间桥梁的作用,在ODBC的驱动程序调用自己的DBMS数据库访问接口时就需要对数据类型进行转换。我们所需要关注的是C语言的数据类型和 ODBC数据类型间的转换关系。
从下图中可以看到ODBC中定义的数据类型和SQL语言中数据类型的对应关系,所以通过下表我们可以将ODBC和SQL语言间的数据一一对应,在后面的文字中我们不再区分ODBC数据类型和SQL语言数据类型。
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
SQL_GUID | |
使用C/C++语言开发,那么必定会在与ODBC语言间存在数据的转换的问题,因为ODBC所存在的一些数据类型在C语言中是不存在的。在ODBC以宏定义的方式定义了C语言和ODBC中使用的数据类型:
| | C语言实际类型 |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | unsigned char * |
| | struct tagDATE_STRUCT { |
| SQL_TIME_STRUCT | } TIME_STRUCT;[a] |
| SQL_TIMESTAMP_STRUCT | struct tagTIMESTAMP_STRUCT { |
| SQL_NUMERIC_STRUCT | } SQL_NUMERIC_STRUCT; |
| | DWORD Data1; WORD Data2; WORD Data3; BYTE Data4[8]; } SQLGUID;[k] |
所以在ODBC的开发过程中不要使用int , float 之类的C语言的实际类型来定义变量而应该使用ODBC定义的数据类型来定义变量,如:SQLINTEGER,SQLFLOAT。
2.2.7
ODBC中的句柄分为三类:环境句柄,数据库连接句柄,SQL语句句柄。
通过图2.4看出,在使用ODBC功能时必须先申请环境句柄,然后在环境句柄的基础上创建数据库连接,最后在数据连接的基础上执行SQL语句。
2.3
为了后面的例子能够顺利执行,请创建一个名称为“test”的DSN,并且使用下面的语句在数据库中创建表和插入基本的数据,这个例子和以后的例子中我们使用SQL Server作为数据库,你需要连接到SQL Server上执行下面的语句来创建表和插入数据。
Create table test_t1(iID int primary key , tmJoin datetime , szName varchar(40) ,fTall float );
Insert into test_t1 values(1, '2002-1-1 15:25' , 'user_1',1.56 );
Insert into test_t1 values(2, '2002-1-2 12:25' , 'user_2',1.53 );
Insert into test_t1 values(3, '2002-1-3 13:25' , 'user_3',1.76 );