QODBC 编译

一、前言

本章节详细介绍 QT QODBC 数据库编程连接,QT 为数据库编程提供了一个类似 JDBC 的统一操作模型,它的底层是具体数据库或数据库接口的插件,由它们负责完成真正的数据库操作。可进入达梦云适配中心下载试用下载 QT 接口源码。

QT 自带 QODBC Driver,在 Windows 平台上通过系统提供的 ODBC Driver 可以访问支持 ODBC 的数据库,如 Ms Access、SQL Server 等( Windows XP 自带 Access 和 SQL Server 的 ODBC Driver)。开发者通过 QODBC 接口连接 DM 数据库。

二、开发环境准备

2.1 达梦数据库版本

名称 版本
DM 数据库 DM 8.0 及以上版本
QT 5.12.1

2.2 达梦数据库安装

请参考数据库环境准备

2.3 QT 开发环境搭建

下载链接:https://download.qt.io/archive/qt/

2.4 注册 ODBC 数据源

请参考 通过 ODBC 连接数据库 章节。

2.5 编译 libqsqlodbc.so

  1. 首先进入 qt 源码目录中修改 qsqldriverbase.pri 文件,将 include 部分修改为下图所示内容。

image.png

image.png

  1. 修改 qt 源码目录中的 odbc.pro 文件,注释 QMAKE_USE += odbc

image.png

image.png

  1. 在/data/Qt5.12.1/5.12.1/gcc_64/bin 下执行。INCLUDEPATH 和 LIBS 的查找方式如下:

image.png

./qmake "INCLUDEPATH+=/usr/local/include" "LIBS+=-L/usr/local/lib -lodbc" /data/Qt5.12.1/5.12.1/Src/qtbase/src/plugins/sqldrivers/odbc/odbc.pro

会在该目录下生成 Makefile 文件,执行 make 即可生成 libqsqlodbc.so,将此动态库复制到 qt 目录下的 sqldrivers 目录下即可正常使用 qodbc 接口对达梦进行操作。

三、数据库连接

3.1 数据库连接示例

QODBC 通过 ODBC 接口登录登出示例程序 qt_conn.c 如下:

#include <QCoreApplication>
#include <QtSql>
#include <QDebug>
#include <QSqlDatabase>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    QSqlDatabase db = QSqlDatabase::addDatabase("QODBC");
    db.setHostName("192.168.104.21");
    db.setPort(51236);
    db.setDatabaseName("DM8");
    db.setUserName("SYSDBA");
    db.setPassword("*****");
    if (db.open())
        qDebug() << "connect ok!";
    else
    {
        qDebug() << "connect fail! " << db.lastError().text().toLatin1();
    }

    return a.exec();
}

2、运行示例截图:

image.png

四、开发示例

4.1 基础操作示例

  1. QODBC 通过 ODBC 接口增、删、改、查四个基本操作,示例程序 qt_dml.c 如下:
#include <QCoreApplication>
#include <QtSql>
#include <QDebug>
#include <QTextCodec>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    QSqlDatabase db = QSqlDatabase::addDatabase("QODBC");
    db.setHostName("192.168.104.21");
    db.setPort(51236);
    db.setDatabaseName("DM8");
    db.setUserName("SYSDBA");
    db.setPassword("*****");
    if (db.open())
        qDebug() << "connect ok!";
    else
    {
        qDebug() << "connect fail! " << db.lastError().text().toLatin1();
    }

    QSqlQuery query;

    //清空表,初始化测试环境
    QString strsql = "delete from PRODUCTION.PRODUCT_CATEGORY";
    query.exec(strsql);


    //插入数据
    strsql = "insert into PRODUCTION.PRODUCT_CATEGORY(NAME) values('语文'), ('数学'), ('英语'), ('体育')";
    if (query.exec(strsql))
    {
        qDebug() << "insert ok!";
    }
    else
    {
        qDebug() << "insert fail! " << query.lastError().text();
        getchar();
        exit(-1);
    }

    //删除数据
    strsql = "delete from PRODUCTION.PRODUCT_CATEGORY where name='数学'";
    if (query.exec(strsql))
    {
        qDebug() << "delete ok!";
    }
    else
    {
        qDebug() << "delete fail! " << query.lastError().text();
        getchar();
        exit(-1);
    }

    //更新数据
    strsql = "update PRODUCTION.PRODUCT_CATEGORY set name = '英语—新课标' where name='英语';";
    if (query.exec(strsql))
    {
        qDebug() << "update ok!";
    }
    else
    {
        qDebug() << "update fail! " << query.lastError().text();
        getchar();
        exit(-1);
    }

    //查询数据
    strsql = "select name from PRODUCTION.PRODUCT_CATEGORY";
    if (query.exec(strsql))
    {
        qDebug() << "select ok!";
    }
    else
    {
        qDebug() << "select fail! " << query.lastError().text();
        getchar();
        exit(-1);
    }
    while (query.next())
    {
         qDebug() << query.value(0).toString().toStdString().c_str();
    }
    query.clear();

    return a.exec();
}
  1. 运行示例截图:

image.png

4.2 绑定变量示例

  1. QODBC 通过 ODBC 接口绑定变量示例程序 qt_bind.c 如下:
#include <QCoreApplication>
#include <QtSql>
#include <QDebug>
#include <QTextCodec>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    QSqlDatabase db = QSqlDatabase::addDatabase("QODBC");
    db.setHostName("192.168.104.21");
    db.setPort(51236);
    db.setDatabaseName("DM8");
    db.setUserName("SYSDBA");
    db.setPassword("*****");
    if (db.open())
        qDebug() << "connect ok!";
    else
    {
        qDebug() << "connect fail! " << db.lastError().text().toLatin1();
    }

    QSqlQuery query;

    //清空表,初始化测试环境
    QString strsql = "delete from PRODUCTION.PRODUCT_CATEGORY";
    query.exec(strsql);


    //绑定参数方式插入数据
    strsql = "insert into PRODUCTION.PRODUCT_CATEGORY(name) values(?)";
    query.prepare(strsql);
    query.bindValue(0, "物理");
    if (query.exec())
    {
        qDebug() << "insert ok!";
    }
    else
    {
        qDebug() << "insert fail! " << query.lastError().text();
        getchar();
        exit(-1);
    }

    //查询数据
    strsql = "select name from PRODUCTION.PRODUCT_CATEGORY";
    if (query.exec(strsql))
    {
        qDebug() << "select ok!";
    }
    else
    {
        qDebug() << "select fail! " << query.lastError().text();
        getchar();
        exit(-1);
    }
    while (query.next())
    {
         qDebug() << query.value(0).toString().toStdString().c_str();
    }
    query.clear();

    return a.exec();
}
  1. 运行示例截图:

image.png

4.3 大字段操作示例

  1. QODBC 通过 ODBC 接口大字段操作包括大字段的插入,查询等。示例程序 qt_lob.c 如下:
#include <QCoreApplication>
#include <QtSql>
#include <QDebug>
#include <QTextCodec>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    QSqlDatabase db = QSqlDatabase::addDatabase("QODBC");
    db.setHostName("192.168.104.21");
    db.setPort(51236);
    db.setDatabaseName("DM8");
    db.setUserName("SYSDBA");
    db.setPassword("*****");
    if (db.open())
        qDebug() << "connect ok!";
    else
    {
        qDebug() << "connect fail! " << db.lastError().text().toLatin1();
    }

    QSqlQuery query;

    //清理测试环境
    QString strsql = "drop table if exists PRODUCTION.BIG_DATA";
    query.exec(strsql);
    strsql = "create table PRODUCTION.BIG_DATA(c1 int, c2 blob)";
    query.exec(strsql);

    // 读取文件数据,写入 lob 列
    //选择要写入的文件
    QString f = "../qt_lob/file/DM8_SQL.pdf";

    //转换为字节数组
    QByteArray mapData;
    QFile file(f);
    file.open(QIODevice::ReadOnly);
    mapData = file.readAll();
    file.close();

    //插入数据
    query.prepare("INSERT INTO PRODUCTION.BIG_DATA values(?, ?)");
    query.bindValue(0, 1);
    query.bindValue(1, mapData);
    if (!query.exec()) {
        qDebug() << query.lastError();
    } else {
        qDebug() << "insert OK!";
    }

    //读取 lob 列数据,写入到文件中
    QSqlQuery readquery;

    QByteArray databa;
    if (readquery.exec("select c2 from PRODUCTION.BIG_DATA")) {
        QSqlRecord myrecord = readquery.record();

        if (readquery.next()) {
            databa = readquery.value(myrecord.indexOf("C2")).toByteArray();
        }
    }

    QFile mybfile("../qt_lob/file/DM81_SQL.pdf");
    mybfile.open(QIODevice::WriteOnly);
    mybfile.write(databa);
    mybfile.close();
    qDebug() << "select OK!";


    return a.exec();
}
  1. 运行示例截图:

image.png

五、常见问题

  1. 首先尽可能使用源码安装的完整版 qt,否则会缺失基础的 libqsqlodbc.so,如果没有安装源码的情况下使用系统自带的 qt,要注意直接下载的源码 src 版本也要和现有 qt 版本一致,否则会出现头文件缺失等问题,该问题是目录结构不匹配导致;

    -isystem /usr/include/aarch64-linux-gnu/qt5/QtSql -isystem /usr/include/aarch64-liunx-gnu/qt5/QtCore -I.moc/debug
    ql_dm.cpp:59:10: fatal error: qsqldriver_p.h; 没有那个文件或目录
             #include<qsqldriver_p.h>
    
  2. 保证 odbc 服务名能够正常进行 isql 测试,否则根据 isql -v dsn 来判断具体原因,大部分都是因为环境变量配置错误导致 libdodbc.so 动态库依赖缺失,arm 平台编译安装 unixodbc 注意加上--build=arm-linux;

  3. 避免系统中安装多版本 qt,会导致环境混乱,libqsqlodbc.so 或者 libqsqldm.so 动态库放入 qt 的 sqldrivers 目录中还是无法识别为可用驱动,driver not loaded,可通过临时 export QT_DEBUG_PLUGINS=1 该窗口下运行程序会打印出具体 qt 的插件 debug 信息,从中看是否从正确的目录搜索到了对应动态库,另外对应动态库是否被识别为 plugins,否则需要去考虑 qt 环境方面问题;

image.png

  1. pro 文件中需要加上 qt+=sql 否则无法识别驱动;
  2. 尽量使用 root 用户打开 qtcreator,避免其他用户环境变量问题导致无法识别一些依赖组件;
  3. qt 中 kit 套件、数据库、odbc 位数需要保持一致。

六、参考

  1. 示例代码下载:qt_qodbc_code.zip
  2. 以上文档内容参考过程中遇到任何问题,可到 达梦技术社区 提问交流。
微信扫码
分享文档
扫一扫
联系客服