第1关:ODBC程序设计
- 任务描述
- 相关知识
- ODBC主要功能
- ODBC接口主要函数
- ODBC应用程序开发实例
- DM ODBC应用程序开发总体流程
- DM ODBC代码编写流程
- DM ODBC代码编写实例
- 编程要求
- 测试说明
- 代码参考:
任务描述
本关任务:使用 ODBC 查询表中数据。
相关知识
为了完成本关任务,你需要掌握:
1.ODBC 的主要功能;
2.ODBC 接口主要函数;
3.ODBC 应用程序开发实例。
ODBC主要功能
ODBC(Open Database Connectivity,开放式数据库连接)是由 Microsoft 开发和定义的一种访问数据库的应用程序接口,其定义了访问数据库API的一组规范,这些API独立于形色各异的数据库系统和编程语言。因此,ODBC 支持不同编程语言,同时也支持不同的数据库系统。借助 ODBC 接口,应用程序能够使用相同的源代码和各种各样的数据库交互。这使得应用程序开发人员不需要考虑各类数据库系统的构造细节,只要使用相应 ODBC 驱动程序,即可通过将 SQL 语句发送到目标数据库中,可以访问和操作各类数据库中的数据。
也就是说,一个基于 ODBC 的应用程序,对数据库的操作不依赖任何数据库系统,所有的数据库操作由对应数据库的ODBC驱动程序完成。不论是 SQL Server、Access、Oracle,还是 DM 数据库,均可借助 ODBC API 进行访问。ODBC 体系结构如下图所示,ODBC 驱动程序管理器用于管理各种 ODBC 驱动程序,基于 ODBC 开发的应用程序通过 ODBC 驱动程序管理器,调用针对不同数据库的驱动程序,进行数据对象的维护、数据的查询和修改等操作。
DM8 数据库提供的 DM ODBC 3.0 接口遵照 Microsoft ODBC 3.0 规范设计与开发,实现了 ODBC 应用程序与 DM 的互连。其由 C 语言编写,其底层调用 DM DCI 接口实现。因此,应用程序开发人员可基于 ODBC 接口规范,使用 DM ODBC 驱动访问和操作 DM8 数据库。
ODBC接口主要函数
由于 DM ODBC 遵照 Microsoft ODBC 3.0 规范设计与开发,因此 DM ODBC 接口提供的函数与标准 ODBC 一致。由于 DM ODBC 接口函数较多,下图仅列出了 DM ODBC 接口的主要函数。
ODBC应用程序开发实例
DM ODBC应用程序开发总体流程
DM ODBC 为程序员提供了基于 ODBC 接口开发应用程序的手段,程序员使用 DM ODBC 开发应用程序时总体流程如下图所示。首先,安装 DM ODBC 驱动;其次,配置 ODBC 数据源;最后,基于 DM ODBC 编程规范,编写代码访问和操作 DM8 数据库。
1)安装 DM ODBC 驱动程序;
示例:
1.将附件 unixODBC-2.3.0.tar.gz 上传到 /usr/local 下,执行安装。
[root@localhost local]# tar -xzvf unixODBC-2.3.0.tar.gz
[root@localhost unixODBC-2.3.0]# cd unixODBC-2.3.0
[root@localhost unixODBC-2.3.0]# ./configure --enable-gui=no
[root@localhost unixODBC-2.3.0]# make
[root@localhost unixODBC-2.3.0]# make install
2.查看操作系统上查看 ODBC 版本
[dmdba@localhost]# odbc_config --version
2.3.0
3.查看 ODBC 配置文件存放的位置
[root@localhost etc]# odbc_config --odbcini
/etc/odbc.ini
[root@localhost etc]# odbc_config --odbcinstini
/etc/odbcinst.ini
4.修改odbc.ini文件
[dmdba@localhost]# vi /etc/odbc.ini
[dm]
Description = DM ODBC DSN
Driver = DM7 ODBC DRIVER
SERVER = localhost
UID = SYSDBA
PWD = SYSDBA
TCP_PORT = 5236
5.修改odbcinst.ini文件
[dmdba@localhost]# vi /etc/odbcinst.ini
[DM7 ODBC DRIVER]
Description = ODBC DRIVER FOR DM7
Driver = /opt/dmdbms/bin/libdodbc.so
6.测试连接
[root@localhost]# isql dm SYSDBA SYSDBA
+---------------------------------------+
| Connected! |
| |
| sql-statement |
| help [tablename] |
| quit |
| |
+---------------------------------------+
出现上述“Connected”就代表安装成功。
2)配置 DM ODBC 数据源;
3)编写 DM ODBC 代码。
DM ODBC代码编写流程
DM ODBC 数据源配置成功后,即可编写代码访问和操作数据库。遵循 ODBC 编程规范,基于 DM ODBC 接口编写代码访问和操作数据库大致流程如下图所示。
首先,创建连接环境和连接数据库。主要通过调用相关函数分配环境句柄、设置环境属性、分配连接句柄和建立数据库连接等过程。
其次,访问和操作数据库。主要通过建立的连接来分配语句句柄、执行SQL语句等操作,该过程是操作数据库的主体部分,与数据库的所有交互均在该过程完成。
最后,断开连接和释放连接资源。数据库操作完成后,程序需关闭数据库连接,并释放连接资源。
DM ODBC代码编写实例
【例1】 基于 DM ODBC 编程接口,利用已配置的 DM ODBC 数据源 DM,编写程序,实现获取数据源 DM 对应数据库中 DMHR.EMPLOYEE 表的数据,包括职员 ID、姓名、手机号码等信息。
在 Visual Studio Code 集成开发环境中,创建一个项目,并为项目添加一个 .cpp 源代码文件;然后添加依赖文件“dodbc.so”和达梦数据库安装目录下的 bin 和 include 两个依赖目录;接着基于 DM ODBC 接口编写代码。
1)创建连接环境和连接数据库
应用程序与 DM 数据库进行通讯,需要和数据库建立连接。①调用函数 SQLAllocHandle 申请环境、连接句柄;②调用函数 SQLSetEnvAttr 设置环境句柄属性;③调用函数 SQLSetConnectAttr 设置连接句柄属性;⑤调用连接函数 SQLConnect、SQLDriverConnect 或 SQLBrowseConnect 连接数据源。
2)访问和操作数据库
与 ODBC 数据源建立连接后,即可通过 ODBC 函数访问和操作数据。调用 SQLAllocHandle 申请语句句柄,通过该句柄执行 SQL 语句;调用函数 SQLPrepare 对 SQL 语句和操作进行准备;调用 SQLDescribeCol、SQLDescribeParam 等函数取得相关的描述信息,依据描述信息调用 SQLBindCol、SQLBindParam 等函数绑定相关的列和参数;调用 SQLExecute 执行 SQL 语句,实现相关的 SQL 操作。应用程序也可以调用 SQLExecDirect 直接执行 SQL 语句进行相关的 SQL 操作。
3)断开数据连接和释放连接资源
数据库操作完成后,程序需关闭数据库连接,并释放连接资源。如果要终止客户程序与服务器之间的连接,客户程序应当完成以下的几个操作:
(1)调用 SQLFreeHandle 释放语句句柄,关闭所有打开的游标,释放相关的语句句柄资源(在非自动提交模式下,需事先提交当前的事务);
(2)调用函数 SQLDisconnect 关闭所有的连接;
(3)调用 SQLFreeHandle 释放连接句柄及其相关的资源;
(4)调用 SQLFreeHandle 释放环境句柄及其相关的资源。
例 1 代码如下所示,该代码可用于查询 dmhr.employee 表中所有职工姓名、id 和电话号码。
#include <sys/socket.h>
#include <unistd.h>
#include <stdio.h>
#include <sql.h>
#include <sqltypes.h>
#include <sqlext.h>
/* 检测返回代码是否为成功标志,当为成功标志返回 TRUE,否则返回 FALSE */
#define RC_SUCCESSFUL(rc) ((rc) == SQL_SUCCESS || (rc) == SQL_SUCCESS_WITH_INFO)
/* 检测返回代码是否为失败标志,当为失败标志返回 TRUE,否则返回 FALSE */
#define RC_NOTSUCCESSFUL(rc) (!(RC_SUCCESSFUL(rc)))
HENV henv; /* 环境句柄 */
HDBC hdbc; /* 连接句柄 */
HSTMT hsmt; /* 语句句柄 */
SQLRETURN sret;/* 返回代码 */
char szpersonid[11]; /*人员编号*/
SQLLEN cbpersonid=0;
char szname[51]; /*人员姓名*/
SQLLEN cbname=0;
char szphone[26]; /*联系电话*/
SQLLEN cbphone=0;
void main(void)
{
/* 申请一个环境句柄 */
SQLAllocHandle(SQL_HANDLE_ENV, NULL, &henv);
if(henv == NULL){
printf("ODBC 环境句柄分配失败");
return;
}
/* 设置环境句柄的 ODBC 版本 */
SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, SQL_IS_INTEGER);
/* 申请一个连接句柄 */
SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);
if(hdbc == NULL){
printf("ODBC 连接句柄分配失败");
return;
}
sret=SQLConnect(hdbc, (SQLCHAR *)"DM", SQL_NTS, (SQLCHAR *)"DMHR", SQL_NTS, (SQLCHAR *)"dameng123", SQL_NTS);
if(sret == SQL_SUCCESS||sret==SQL_SUCCESS_WITH_INFO){
/* 申请一个语句句柄 */
SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hsmt);
/* 立即执行查询人员信息表的语句 */
SQLExecDirect(hsmt, (SQLCHAR *)"SELECT employee_id, employee_name, phone_num FROM dmhr.employee;", SQL_NTS);
/* 绑定数据缓冲区 */
SQLBindCol(hsmt, 1, SQL_C_CHAR, szpersonid, sizeof(szpersonid), &cbpersonid);
SQLBindCol(hsmt, 2, SQL_C_CHAR, szname, sizeof(szname), &cbname);
SQLBindCol(hsmt, 3, SQL_C_CHAR, szphone, sizeof(sazphone), &cbphone);
/* 取得数据并且打印数据 */
printf("人员编号 人员姓名 联系电话\n");
for (;;) {
sret = SQLFetchScroll(hsmt, SQL_FETCH_NEXT, 0);
if (sret == SQL_NO_DATA_FOUND)
break;
printf("%s %s %s\n", szpersonid, szname, szphone);
}
}
else{
printf("连接失败\n");
}
/* 关闭游标,终止语句执行 */
SQLCloseCursor(hsmt);
/* 释放语句句柄 */
SQLFreeHandle(SQL_HANDLE_STMT, hsmt);
/* 断开与数据源之间的连接 */
SQLDisconnect(hdbc);
/* 释放连接句柄 */
SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
/* 释放环境句柄*/
SQLFreeHandle(SQL_HANDLE_ENV, henv);
}
其中 DMHR 为用户名,dameng123 为密码。
编程要求
使用右侧 VS CODE 编写 ODBC 程序,查询 test.tb_class 表中所有数据。
登录用户名为:SYSDBA;密码:SYSDBA。
操作步骤:
1.打开 VS CODE,在 HELLOWORLD 项目下方新建 test.cpp 文件,并在该文件中实现 ODBC 程序需求;
2.编辑 HELLOWORLD 项目下的 task.json 文件,按下图所示添加依赖文件dodbc.so。
4.选中 test.c 文件,按下“Ctrl+Shift+B”,编译 test.cpp 文件;
5.点击测评。
test.tb_class 表字段信息:
字段名 | 字段类型 |
---|---|
id | int |
name | varchar(25) |
测试说明
平台会对你编写的代码进行测试。
开始你的任务吧,祝你成功!
代码参考:
- 打开 VS CODE,编辑 HELLOWORLD 项目下的 task.json 文件,加上代码:
“-dodbc”,
- 在 HELLOWORLD 项目下方新建 test.cpp 文件,复制以下代码:
(点击右侧的 “工具栏”->“复制粘贴” 即可粘贴进去了)
#include <sys/socket.h>
#include <unistd.h>
#include <stdio.h>
#include <sql.h>
#include <sqltypes.h>
#include <sqlext.h>
/* 检测返回代码是否为成功标志,当为成功标志返回 TRUE,否则返回 FALSE */
#define RC_SUCCESSFUL(rc) ((rc) == SQL_SUCCESS || (rc) == SQL_SUCCESS_WITH_INFO)
/* 检测返回代码是否为失败标志,当为失败标志返回 TRUE,否则返回 FALSE */
#define RC_NOTSUCCESSFUL(rc) (!(RC_SUCCESSFUL(rc)))
HENV henv; /* 环境句柄 */
HDBC hdbc; /* 连接句柄 */
HSTMT hsmt; /* 语句句柄 */
SQLRETURN sret;/* 返回代码 */
int szpersonid; /*人员编号*/
SQLLEN cbpersonid=0;
char szname[51]; /*人员姓名*/
SQLLEN cbname=0;
int main(void)
{
/* 申请一个环境句柄 */
SQLAllocHandle(SQL_HANDLE_ENV, NULL, &henv);
if(henv == NULL){
printf("ODBC 环境句柄分配失败");
return -1;
}
/* 设置环境句柄的 ODBC 版本 */
SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, SQL_IS_INTEGER);
/* 申请一个连接句柄 */
SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);
if(hdbc == NULL){
printf("ODBC 连接句柄分配失败");
return -1;
}
sret=SQLConnect(hdbc, (SQLCHAR *)"DM", SQL_NTS, (SQLCHAR *)"SYSDBA", SQL_NTS, (SQLCHAR *)"SYSDBA", SQL_NTS);
if(sret == SQL_SUCCESS||sret==SQL_SUCCESS_WITH_INFO){
/* 申请一个语句句柄 */
SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hsmt);
/* 立即执行查询人员信息表的语句 */
SQLExecDirect(hsmt, (SQLCHAR *)"SELECT id, name FROM test.tb_class;", SQL_NTS);
/* 绑定数据缓冲区 */
SQLBindCol(hsmt, 1, SQL_C_CHAR, &szpersonid, sizeof(szpersonid), &cbpersonid);
SQLBindCol(hsmt, 2, SQL_C_CHAR, szname, sizeof(szname), &cbname);
/* 取得数据并且打印数据 */
for (int i = 1;;++i) {
sret = SQLFetchScroll(hsmt, SQL_FETCH_NEXT, 0);
if (sret == SQL_NO_DATA_FOUND)
break;
printf("%d %s\n", i, szname);
}
}
else{
printf("连接失败\n");
}
/* 关闭游标,终止语句执行 */
SQLCloseCursor(hsmt);
/* 释放语句句柄 */
SQLFreeHandle(SQL_HANDLE_STMT, hsmt);
/* 断开与数据源之间的连接 */
SQLDisconnect(hdbc);
/* 释放连接句柄 */
SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
/* 释放环境句柄*/
SQLFreeHandle(SQL_HANDLE_ENV, henv);
return 0;
}