• 第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
    
    • 1
    • 2
    • 3
    • 4
    • 5

    2.查看操作系统上查看 ODBC 版本

    [dmdba@localhost]# odbc_config --version
    2.3.0
    
    • 1
    • 2

    3.查看 ODBC 配置文件存放的位置

    [root@localhost etc]# odbc_config --odbcini
    /etc/odbc.ini
    [root@localhost etc]# odbc_config --odbcinstini
    /etc/odbcinst.ini
    
    • 1
    • 2
    • 3
    • 4

    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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    5.修改odbcinst.ini文件

    [dmdba@localhost]# vi /etc/odbcinst.ini
    [DM7 ODBC DRIVER]
    Description = ODBC DRIVER FOR DM7
    Driver = /opt/dmdbms/bin/libdodbc.so
    
    • 1
    • 2
    • 3
    • 4

    6.测试连接

    [root@localhost]# isql dm SYSDBA SYSDBA
    +---------------------------------------+
    | Connected!                            |
    |                                       |
    | sql-statement                         |
    | help [tablename]                      |
    | quit                                  |
    |                                       |
    +---------------------------------------+
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    出现上述“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  
    #include 
    #include 
    #include 
    #include 
    #include 
    /* 检测返回代码是否为成功标志,当为成功标志返回 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);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69

    其中 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 表字段信息:

    字段名字段类型
    idint
    namevarchar(25)

    测试说明

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


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

    代码参考:

    1. 打开 VS CODE,编辑 HELLOWORLD 项目下的 task.json 文件,加上代码:“-dodbc”,
      路径参考
    2. 在 HELLOWORLD 项目下方新建 test.cpp 文件,复制以下代码:
      (点击右侧的 “工具栏”->“复制粘贴” 即可粘贴进去了)
      复制示例
    3. 选中 test.c 文件,按下“Ctrl+Shift+B”,编译 test.cpp 文件;
    #include  
    #include 
    #include 
    #include 
    #include 
    #include 
    /* 检测返回代码是否为成功标志,当为成功标志返回 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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
  • 相关阅读:
    【Python高级编程】Python中Excel表格处理数据
    设计模式之观察者模式
    0015Java程序设计-springboot美食网站
    DNA-CuInSeQDs近红外CuInSe量子点包裹脱氧核糖核酸DNA
    蓝桥杯每日一题2023.10.5
    Apache软件基金会的孵化标准和毕业标准
    nvm、node、npm解决问题过程记录
    通过Web网管切换到命令行界面【华为路由器】
    python使用dataset快速使用SQLite
    虚拟滚动(Virtual Scrolling)实现
  • 原文地址:https://blog.csdn.net/qq_46373141/article/details/130891984