第1关: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)

测试说明

平台会对你编写的代码进行测试。


开始你的任务吧,祝你成功!

代码参考:

  1. 打开 VS CODE,编辑 HELLOWORLD 项目下的 task.json 文件,加上代码:“-dodbc”,
    路径参考
  2. 在 HELLOWORLD 项目下方新建 test.cpp 文件,复制以下代码:
    (点击右侧的 “工具栏”->“复制粘贴” 即可粘贴进去了)
    复制示例
  3. 选中 test.c 文件,按下“Ctrl+Shift+B”,编译 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;
}

猜你喜欢

转载自blog.csdn.net/qq_46373141/article/details/130891984