Qt连接数据库的两种方法

Qt连接数据库

我曾经想过,无论在哪个平台下开发,都不要再接触SQL Server了,但显然不行。我们是来看世界的,不是来改变世界的,想通就好。

前两天,尝试了一下Qt下远程访问数据库。在macOS下,用Qt 5.11写个程序来远程访问Win10下的SQL Server和My SQL数据库,Qt中通过QSqlDatabase来创建一个数据库连接。简单来说,QSqlDatabase连接数据库可以分为两种方式,聊到这两种方式,就要大概的说一下数据访问的前因后果,以微软的数据访问历史为例,本文只是从快速使用的角度出发,不会讲得太详细深入。

一、 数据访问方式的历史

在早期时,由于数据库种类繁多,各种数据库连接有不同的需求,数据库连接主要依靠各种API函数来进行连接,数据库编程都是直接操作数据库厂商提供的API,每个数据库厂商的提供的数据库操作的API都不相同,如调用函数,操作语句等等。因此每个应用程序都只能对应一个数据库。如果想换数据库,需要重写一遍数据库操作代码,这样的代价是非常大的。因此Microsoft就联合一些厂家做了个接口标准——ODBC。

ODBC(Open Database Connectivity,开放数据库互连)

1992年Microsoft和Sybase、Digital共同制定了ODBC 接口标准,以标准的ODBC API来存取各种不同的数据库。ODBC将所有数据库特定的,底层的操作细节(CLI)封装在驱动(drive)中,并提供一套标准的函数调用。使用时,ODBC会动态地加载数据库的CLI,将函数调用转换成各个数据库的CLI调用。这样应用程序与数据库API本身就隔绝开了,ODBC本身也提供了对SQL语言的支持,用户可以直接将SQL语句送给ODBC,如下图所示。


ODBC流图

这样访问所有的关系型数据库都可以使用一套标准的ODBC API即可。ODBC成为最早的通用数据库访问技术。随后ODBC便获得了许多数据库厂商和Third-Party的支持而逐渐成为标准的数据存取技术。
ODBC以当时的业界标准规范X/OpenCall-LevelInterface(CLI)和ISO/IEC9075-3Call-LevelInterface(SQL/CLI)为涵盖的范围,因而支持了广阔的数据库。虽然ODBC在初期的版本中执行效率不佳,而且功能有限,因此也为人们所贬低。但是,随着Microsoft不断地改善ODBC,使ODBC的执行效率不断增加,ODBC驱动程序的功能也日渐齐全。到目前,ODBC已经是一个稳定并且执行效率良好的数据存取引擎。

OLE DB(Object Linking and Embedding DataBase,对象链接和嵌入数据库)

ODBC是最早的通用数据访问技术,但是ODBC只限于检索关系型数据库的数据。
1997年, Microsoft 的一个战略性系统级编程接口,用于管理整个组织内的数据。OLE DB 是建立在 ODBC 功能之上的一个开放规范。ODBC 是为访问关系型数据库而专门开发的,OLE DB 则用于访问关系型和非关系型信息源,例如主机 ISAM/VSAM 和层次数据库,电子邮件和文件系统存储,文本、图形和地理数据以及自定义业务对象。
在OLE DB中,不再有drive的概念,取而代之的是提供者(provider),每个数据库厂商都需要对象的OLE DB provider。需要注意的是,provider实现了基于COM的接口,这些接口封装了访问数据库的操作细节(CLI)。那么应用程序使用这些通用的接口来进行数据库的访问,而不用考虑数据库的细节。所以,可以理解OLE DB是规定了数据使用者和提供者之间达成了一种协议。
为了兼容一些没有提供provider的数据库,OLE DB也可以基于ODBC,即provider是基于ODBC实现的。这种实现会经过两层,效率会比较低。由于目前大多数数据库都提供了provider,所以这种方式比较少见。 可以看到,OLE DB与ODBC类似,但是原理上是不相同的。如下图。


OLE DB流图
ADO(ActiveX Data Object,ActiveX数据对象)

微软为了简化OLE DB接口,推出了ADO来封装OLE DB的接口,实现与数据库的通信,使得用户更易于调用数据库相关操作。ADO实际上是位于OLE DB顶部的一个附加层(也就是位于OLE DB与应用程序之间),它封装了OLE DB。
ADO被设计来继承微软早期的数据访问对象层,包括RDO(Remote DataObjects)和DAO(Data Access Objects)。随着.NET推出,微软进一步进行升级ADO为ADO.NET。


数据访问历史

二、Qt选程访问数据

本开发环境在macOS平台下,用Qt 5.11开发程序来远程访问Win10下的数据库。使用Parallesl安装一个Win10 虚拟机,IP地址为10.211.55.4,在Win10中安装了Visual Studio Community 2017、SQL Server 2008 Express、MySQL Community 8.0.14。
在Qt中,QSqlDatabase类提供一个通过数据库连接来访问数据库的接口。一个QSqlDatabase的实例代表了一个数据库连接。数据库连接通过数据库驱动提供对数据库的访问,数据库驱动继承自QSqlDriver。
QSqlDatabase 当前支持的驱动类型如下:


QSqlDatabase available driver types
基于ODBC连接数据库

准备工作1:安装odbc manager, 不装第二步会报错
下载地址: http://www.odbcmanager.net/
准备工作2:安装mysql odbc connector
下载地址: https://dev.mysql.com/downloads/connector/odbc/
开始编码。
首先,在Qt的工程文件中加入:

QT       += sql

在源代码文件中引用以下头文件,其中QPluginLoader、QDebug是为了调试用的:

#include <QSqlDatabase>
#include <QSqlError>
#include <QPluginLoader>
#include <QDebug>

先写个loadPlugin函数来检测Qt 有没编译好的ODBC驱动,在 /Users/Hula/Qt/5.11.2/clang_64/plugins/sqldrivers/libqsqlodbc.dylib 对应填上你自己的Qt安装文件路径,代码如下:

void HDbm::loadPlugin()
{
    QPluginLoader loader;
    // ODBC 驱动插件的路径
    loader.setFileName("/Users/Hula/Qt/5.11.2/clang_64/plugins/sqldrivers/libqsqlodbc.dylib");
    qDebug() << loader.load();
    qDebug() << loader.errorString();
}

简单的写个数据库连接函数:

int HDbm::createSQLServerConnection()
{
    loadPlugin();

    QString strHost = "10.211.55.4";
    int port = 3306;
    QString strDbName = "SQLData";
    QString strUserName = "test";
    QString strUserPwd = "123321";
    QSqlDatabase db = QSqlDatabase::addDatabase("QODBC");
    QString strconn = QString("Driver={sql server};SERVER=%1;PORT=%2;DATABASE=%3;UID=%4;PWD=%5;")
                          .arg(strHost)
                          .arg(port)
                          .arg(strDbName)
                          .arg(strUserName)
                          .arg(strUserPwd);
    db.setDatabaseName(strconn);
    if (!db.open())
    {
        qDebug() <<"error_SqlServer:" << db.lastError().text();
        return 1201;
    }

    return 0;
}

调用createSQLServerConnection函数即可。
如果出现以下错误:

The shared library was not found.
QSqlDatabase: QODBC driver not loaded ((null):0, (null))

表示Qt没有 libqsqlodbc 驱动,需要自己动手编译Qt的源码,具体方法自动上网搜索。

使用Qt的QSqlDriver 数据库驱动连接数据库

首先安装MySQL Connector/C,MySQL官网上没有此安装文件,有两种方法来完成,一是用 brew 安装 MySQL,brew 将 MySQL 安装在 usr⁩/⁨local⁩/⁨lib/mysql 目录下,由于Qt 调用 ⁨usr⁩/⁨local⁩/⁨lib⁩ 下的 MySQL 驱动,因此将 usr⁩/⁨local⁩/⁨lib/mysql 目录下的驱动文件 libmysqlclient.dylib 链接到 usr⁩/⁨local⁩/⁨lib 目录下即可。
或从 https://dev.mysql.com/downloads/mysql/ 下载MySQL Community Server的压缩包,解压后,拷贝 lib 目录中文件到 usr⁩/⁨local⁩/⁨lib 下即可。

同上,MySQL数据库连接函数:

int HDbm::createMySQLConnection()
{
    loadPlugin();

    QString strHost = "10.211.55.4";
    int port = 3306;
    QString strDbName = "SQLData";
    QString strUserName = "test";
    QString strUserPwd = "123321";
    QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL");
    // 防止连接超时无反应,设置连接超时3秒
    db.setConnectOptions("MYSQL_OPT_CONNECT_TIMEOUT=3");
    db.setHostName(strHost);
    db.setPort(port);
    db.setDatabaseName(strDbName);
    db.setUserName(strUserName);
    db.setPassword(strUserPwd);
    if (!db.open())
    {
        qDebug() <<"error_SqlServer:" << db.lastError().text();
        return 1201;
    }

    return 0;
}
三、补充说明

在Qt的文档中对QSqlDatabase这个类的描述如下:

The QSqlDatabase class handles a connection to a database.
The QSqlDatabase class provides an interface for accessing a database through a connection. An instance of QSqlDatabase represents the connection. The connection provides access to the database via one of the supported database drivers, which are derived from QSqlDriver. Alternatively, you can subclass your own database driver from QSqlDriver. See How to Write Your Own Database Driver for more information.

如果你使用的数据库不在上表Qt当前支持的驱动类型中,你可以从QSqlDriver类构建你自己的数据库驱动。有两种方法,一是找到数据库厂商的 for ODBC dirver,如果没有,也可以通过数据库厂商的 for C/C++ dirver 自己封装一个 for ODBC dirver,通过 ODBC 访问数据库;再就是从QSqlDriver类构建一个的数据库驱动,来调用数据库厂商的 for C dirver,更为方便简单。

ODBC不同数据库连接字符串:

access 
"Driver={microsoft access driver(*.mdb)};dbq=*.mdb;uid=admin;pwd=pass;"

dBase
 "Driver={microsoft dbase driver(*.dbf)};driverid=277;dbq=***;"

oracle 
"Driver={microsoft odbc for oracle};server=oraclesever.world;uid=admin;pwd=pass;"

MSSQL server 
"Driver={sql server};server=servername;database=dbname;uid=sa;pwd=pass;"

MS text 
"Driver={microsoft text driver(*.txt; *.csv)};dbq=**;extensions=asc,csv,tab,txt;Persist SecurityInfo=false;"

Visual Foxpro
 "Driver={microsoft Visual Foxpro driver};sourcetype=DBC;sourceDB=*.dbc;Exclusive=No;"

MySQL 
"Driver={mysql};database=yourdatabase;uid=username;pwd=yourpassword;option=16386;"

SQLite 
"Driver={SQLite3 ODBC Driver};Database=D:\SQLite\*.db"

PostgreSQL 
"Driver={PostgreSQL ANSI};server=127.0.0.1;uid=admin;pwd=pass;database=databaseName"
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,242评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,769评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,484评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,133评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,007评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,080评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,496评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,190评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,464评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,549评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,330评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,205评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,567评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,889评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,160评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,475评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,650评论 2 335

推荐阅读更多精彩内容