ODBC优点
移植性好
能同时访问不同的数据库
共享多个数据资源
ODBC概述
ODBC产生的原因
由于不同的数据库管理系统的存在,在某个关系数据库管理系统下编写的应用程序就不能在另一个关系数据库管理系统下运行
许多应用程序需要共享多个部门的数据资源,访问不同的关系数据库管理系统
ODBC
是微软公司开放服务体系(Windows Open Services Architecture,WOSA)中有关数据库的一个组成部分
提供了一组访问数据库的应用程序编程接口(Application Programming Interface,API )
ODBC约束力
规范应用开发
规范关系数据库管理系统应用接口
ODBC工作原理概述
ODBC应用系统的体系结构
1.用户应用程序
2.ODBC驱动程序管理器
3.数据库驱动程序
4.数据源
用户应用程序
ODBC应用程序包括的内容
请求连接数据库
向数据源发送SQL语句
为SQL语句执行结果分配存储空间,定义所读取的数据格式
获取数据库操作结果或处理错误
进行数据处理并向用户提交处理结果
请求事务的提交和回滚操作
断开与数据源的连接
ODBC驱动程序管理器
驱动程序管理器:用来管理各种驱动程序
包含在ODBC32.DLL中
管理应用程序和驱动程序之间的通信
建立、配置或删除数据源,并查看系统当前所安装的数据库ODBC驱动程序
主要功能:
装载ODBC驱动程序
选择和连接正确的驱动程序
管理数据源
检查ODBC调用参数的合法性
记录ODBC函数的调用等
数据库驱动程序
ODBC通过驱动程序来提供应用系统与数据库平台的独立性
ODBC应用程序不能直接存取数据库
其各种操作请求由驱动程序管理器提交给某个关系数据库管理系统的ODBC驱动程序
通过调用驱动程序所支持的函数来存取数据库
数据库的操作结果也通过驱动程序返回给应用程序
如果应用程序要操纵不同的数据库,就要动态地链接到不同的驱动程序上
ODBC驱动程序类型
单束
数据源和应用程序在同一台机器上
驱动程序直接完成对数据文件的I/O操作
驱动程序相当于数据管理器
多束
支持客户机—服务器、客户机—应用服务器/数据库服务器等网络环境下的数据访问
由驱动程序完成数据库访问请求的提交和结果集接收
应用程序使用驱动程序提供的结果集管理接口操纵执行后的结果数据
ODBC数据源管理
数据源:是最终用户需要访问的数据,包含了数据库位置和数据库类型等信息,是一种数据连接的抽象
数据源对最终用户是透明的
ODBC给每个被访问的数据源指定唯一的数据源名(Data Source Name,简称DSN),并映射到所有必要的、用来存取数据的低层软件
在连接中,用数据源名来代表用户名、服务器名、所连接的数据库名等
最终用户无须知道数据库管理系统或其他数据管理软件、网络以及有关ODBC驱动程序的细节
例如,假设某个学校在SQL Server和KingbaseES上创建了两个数据库:学校人事数据库和教学科研数据库。
学校的信息系统要从这两个数据库中存取数据
为了方便地与两个数据库连接,为学校人事数据库创建一个数据源名PERSON,为教学科研数据库创建一个名为EDU的数据源
当要访问每一个数据库时,只要与PERSON和EDU连接即可,不需要记住使用的驱动程序、服务器名称、数据库名
ODBC API 基础
ODBC 应用程序编程接口的一致性
API一致性
包含核心级、扩展1级、扩展2级
语法一致性
包含最低限度SQL语法级、核心SQL语法级、扩展SQL语法级
函数概述
ODBC 3.0 标准提供了76个函数接口
分配和释放环境句柄、连接句柄、语句句柄
连接函数(SQLDriverconnect等)
与信息相关的函数(SQLGetinfo、SQLGetFuction等)
事务处理函数(如SQLEndTran)
执行相关函数(SQLExecdirect、SQLExecute等)
编目函数,ODBC 3.0提供了11个编目函数,如SQLTables、SQLColumn等。应用程序可以通过对编目函数的调用来获取数据字典的信息,如权限、表结构等
ODBC不同版本上的函数和函数使用是有差异的,读者必须注意使用的版本,目前最新的版本是ODBC 3.8
句柄及其属性
句柄是32位整数值,代表一个指针
ODBC 3.0中句柄分类
环境句柄
连接句柄
语句句柄
描述符句柄
应用程序句柄之间的关系
每个ODBC应用程序需要建立一个ODBC环境,分配一个环境句柄,存取数据的全局性背景,如环境状态、当前环境状态诊断、当前在环境上分配的连接句柄等
一个环境句柄可以建立多个连接句柄,每一个连接句柄实现与一个数据源之间的连接
在一个连接中可以建立多个语句句柄,它不只是一个SQL语句,还包括SQL语句产生的结果集以及相关的信息等
在ODBC 3.0中又提出了描述符句柄的概念,它是描述SQL语句的参数、结果集列的元数据集合
数据类型
ODBC数据类型
SQL数据类型:用于数据源
C数据类型 :用于应用程序的C代码
应用程序可以通过SQLGetTypeInfo来获取不同的驱动程序对于数据类型的支持情况
SQL数据类型和C数据类型之间的转换规则
ODBC的工作流程
[例8.11] 将KingbaseES数据库中Student表的数据备份到SQL Server数据库中。
该应用涉及两个不同的关系数据库管理系统中的数据源
使用ODBC来开发应用程序,只要改变应用程序中连接函数(SQLConnect)的参数,就可以连接不同关系数据库管理系统的驱动程序,连接两个数据源
在应用程序运行前,已经在KingbaseES和SQL Server中分别建立了Student关系表
应用程序要执行的操作
在KingbaseES上执行SELECT * FROM Student;
把获取的结果集,通过多次执行INSERT语句插入到SQL Server的Student表中
操作步骤
1.配置数据源
2. 初始化环境
3. 建立连接
4. 分配语句句柄
5. 执行SQL语句
6. 结果集处理
7. 中止处理
配置数据源
配置数据源有两种方法
运行数据源管理工具来进行配置
使用Driver Manager 提供的ConfigDsn函数来增加、修改或删除数据源
在[例8.12]中,采用第一种方法创建数据源。因为要同时用到KingbaseES和SQL Server,所以分别建立两个数据源,将其取名为KingbaseES ODBC和SQL Server
[例8.12] 创建数据源的详细过程
#include <stdlib.h>
#include <stdio.h>
#include <windows.h>
#include <sql.h>
#include <sqlext.h>
#include <Sqltypes.h>
#define SNO_LEN 30
#define NAME_LEN 50
#define DEPART_LEN 100
#define SSEX_LEN 5
创建数据源—第一步:定义句柄和变量
int main()
{ /* Step 1 定义句柄和变量 *//*以king开头的表示的是连接KingbaseES的变量*//*以server开头的表示的是连接SQLServer的变量*/SQLHENV kinghenv,serverhenv; /*环境句柄*/SQLHDBC kinghdbc,serverhdbc; /*连接句柄*/SQLHSTMT kinghstmt,serverhstmt; /*语句句柄*/SQLRETURN ret;SQLCHAR sName[NAME_LEN],sDepart[DEPART_LEN],sSex[SSEX_LEN],sSno[SNO_LEN];SQLINTEGER sAge;SQLINTEGER cbAge=0,cbSno=SQL_NTS,cbSex=SQL_NTS,cbName=SQL_NTS,cbDepart=SQL_NTS;
初始化环境
没有和具体的驱动程序相关联,由Driver Manager来进行控制 ,并配置环境属性
应用程序通过调用连接函数和某个数据源进行连接后,Driver Manager才调用所连的驱动程序中的SQLAllocHandle,来真正分配环境句柄的数据结构
创建数据源—第二步:初始化环境
/* Step 2 初始化环境 */
ret=SQLAllocHandle(SQL_HANDLE_ENV,SQL_NULL_HANDLE, &kinghenv);
ret=SQLAllocHandle(SQL_HANDLE_ENV,SQL_NULL_HANDLE, &serverhenv);
ret=SQLSetEnvAttr(kinghenv,SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0);
ret=SQLSetEnvAttr(serverhenv,SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0);
建立连接
应用程序调用SQLAllocHandle分配连接句柄,通过SQLConnect、SQLDriverConnect或SQLBrowseConnect与数据源连接
SQLConnect连接函数的输入参数为:
配置好的数据源名称
用户ID
口令
[例8.12]中KingbaseES ODBC为数据源名字,SYSTEM为用户名,MANAGER为用户密码
创建数据源—第三步:建立连接
/* Step 3 建立连接 */
ret=SQLAllocHandle(SQL_HANDLE_DBC, kinghenv, &kinghdbc);
ret=SQLAllocHandle(SQL_HANDLE_DBC, serverhenv, &serverhdbc);
ret=SQLConnect(kinghdbc,“KingbaseES ODBC”, SQL_NTS,“SYSTEM”,SQL_NTS, "MANAGER",SQL_NTS);
if (!SQL_SUCCEEDED(ret)) /*连接失败时返回错误值*/return -1;
ret=SQLConnect(serverhdbc, "SQLServer", SQL_NTS, "sa“,SQL_NTS,"sa",SQL_NTS);
if (!SQL_SUCCEEDED(ret) ) /*连接失败时返回错误值*/return -1;
分配语句句柄
处理任何SQL语句之前,应用程序还需要首先分配一个语句句柄
语句句柄含有具体的SQL语句以及输出的结果集等信息
应用程序还可以通过SQLtStmtAttr来设置语句属性(也可以使用默认值)
创建数据源—第四步
/* Step 4 初始化语句句柄 */
ret=SQLAllocHandle(SQL_HANDLE_STMT,kinghdbc,&kinghstmt);
ret=SQLSetStmtAttr(kinghstmt,SQL_ATTR_ROW_BIND_TYPE, (SQLPOINTER)SQL_BIND_BY_COLUMN, SQL_IS_INTEGER);
ret=SQLAllocHandle(SQL_HANDLE_STMT,serverhdbc, &serverhstmt);
执行SQL语句
应用程序处理SQL语句的两种方式
预处理(SQLPrepare、SQLExecute适用于语句的多次执行)
直接执行(SQLExecdirect)
如果SQL语句含有参数,应用程序为每个参数调用SQLBindParameter,并把它们绑定至应用程序变量
应用程序可以直接通过改变应用程序缓冲区的内容从而在程序中动态改变SQL语句的具体执行
应用程序根据语句类型进行的处理
有结果集的语句(select或是编目函数),则进行结果集处理
没有结果集的函数,可以直接利用本语句句柄继续执行新的语句或是获取行计数(本次执行所影响的行数)之后继续执行
在插入数据时,采用了预编译的方式,首先通过SQLPrepare来预处理SQL语句,然后将每一列绑定到用户缓冲区
创建数据源—第五步:执行SQL语句
/* Step 5 两种方式执行语句 */
/* 预编译带有参数的语句 */
ret=SQLPrepare(serverhstmt,"INSERT INTO STUDENT(SNO,SNAME,SSEX, SAGE,SDEPT) VALUES (?, ?, ?, ?, ?)", SQL_NTS);
if (ret==SQL_SUCCESS || ret==SQL_SUCCESS_WITH_INFO)
{ret=SQLBindParameter(serverhstmt,1,SQL_PARAM_INPUT,SQL_C_CHAR,SQL_CHAR,SNO_LEN,0,sSno,0, &cbSno); ret=SQLBindParameter(serverhstmt,2,SQL_PARAM_INPUT, SQL_C_CHAR,SQL_CHAR,NAME_LEN,0,sName,0,&cbName);ret=SQLBindParameter(serverhstmt,3,SQL_PARAM_INPUT,SQL_C_CHAR,SQL_CHAR,2,0,sSex,0,&cbSex);ret=SQLBindParameter(serverhstmt,4,SQL_PARAM_INPUT,SQL_C_LONG,SQL_INTEGER,0,0,&sAge,0,&cbAge);
ret=SQLBindParameter(serverhstmt,5,SQL_PARAM_INPUT, SQL_C_CHAR,SQL_CHAR, DEPART_LEN, 0, sDepart,0, &cbDepart);}/*执行SQL语句*/
ret=SQLExecDirect(kinghstmt,"SELECT * FROM STUDENT",SQL_NTS);
if (ret==SQL_SUCCESS || ret==SQL_SUCCESS_WITH_INFO)
{
ret=SQLBindCol(kinghstmt,1,SQL_C_CHAR,sSno,SNO_LEN,&cbSno);
ret=SQLBindCol(kinghstmt,2,SQL_C_CHAR,sName,NAME_LEN,&cbName);
ret=SQLBindCol(kinghstmt,3,SQL_C_CHAR,sSex,SSEX_LEN,&cbSex);
ret=SQLBindCol(kinghstmt,4,SQL_C_LONG,&sAge,0,&cbAge);
ret=SQLBindCol(kinghstmt,5,SQL_C_CHAR,sDepart, DEPART_LEN,&cbDepart);
}
结果集处理
应用程序可以通过SQLNumResultCols来获取结果集中的列数
通过SQL DescribeCol或是SQLColAttrbute函数来获取结果集每一列的名称、数据类型、精度和范围
ODBC中使用游标来处理结果集数据
ODBC中游标类型
Forward-only游标,是ODBC的默认游标类型
可滚动(Scroll)游标
静态(static)
动态(dynamic)
码集驱动(keyset-driven)
混合型(mixed)
结果集处理步骤
ODBC游标的打开方式不同于嵌入式SQL,不是显式声明而是系统自动产生一个游标,当结果集刚刚生成时,游标指向第一行数据之前
应用程序通过SQLBindCol把查询结果绑定到应用程序缓冲区中,通过SQLFetch或是SQLFetchScroll来移动游标获取结果集中的每一行数据
对于如图像这类特别的数据类型,当一个缓冲区不足以容纳所有的数据时,可以通过SQLGetdata分多次获取
最后通过SQLClosecursor来关闭游标
创建数据源—第六步:结果集处理
/* Step 6 处理结果集并执行预编译后的语句*/
while ((ret=SQLFetch(kinghstmt))!=SQL_NO_DATA_FOUND) {
if(ret==SQL_ERROR)printf("Fetch error\n");
else ret=SQLExecute(serverhstmt);
}
中止处理
应用程序中止步骤
释放语句句柄
释放数据库连接
与数据库服务器断开
释放ODBC环境
创建数据源—第七步:中止处理
/* Step 7 中止处理*/
SQLFreeHandle(SQL_HANDLE_STMT,kinghstmt);
SQLDisconnect(kinghdbc);
SQLFreeHandle(SQL_HANDLE_DBC,kinghdbc);
SQLFreeHandle(SQL_HANDLE_ENV,kinghenv);
SQLFreeHandle(SQL_HANDLE_STMT,serverhstmt);
SQLDisconnect(serverhdbc);
SQLFreeHandle(SQL_HANDLE_DBC,serverhdbc);
SQLFreeHandle(SQL_HANDLE_ENV,serverhenv);
return 0;
}
欢迎大家加我微信交流讨论(请备注csdn上添加)