Qt扫盲-数据库编程综述

一、概述

Qt SQL是支持SQL数据库的一个重要模块。Qt SQL的api分为不同的层。

  • Driver 层
  • SQL API 层
  • User Interface 层

要在项目中启用Qt SQL,请在c++文件中添加以下指令:

#include <QtSql>

要链接到Qt SQL模块,在 pro 项目文件中添加以下行:

QT += sql

我们应该具备SQL的基本知识。应该能够理解简单的SELECT、INSERT、UPDATE和DELETE语句。尽管QSqlTableModel类提供了数据库浏览和编辑的接口,而不需要SQL的知识,但强烈建议对SQL有基本的了解。

我一般暂时还使用的是 SQL API层 API,偶尔会使用 User Interface 层,因为User Interface 封装好了一些基础的模型,只需要简单的映射一些就行,那个是属于高层API的,那个可以提高开发效率的。

这里后面的使用 model 类 后面单独记录一下

二、数据库模块的类

类名功能
QSql包含在Qt SQL模块中使用的其他标识符
QSqlDatabase处理与数据库的连接相关
QSqlDriver用于访问特定SQL数据库的抽象基类
QSqlDriverCreator为特定驱动程序类型提供SQL驱动程序工厂的模板类
QSqlDriverCreatorBaseSQL驱动程序工厂的基类
QSqlErrorSQL数据库错误信息
QSqlField操作SQL数据库表和视图中的字段
QSqlIndex操作和描述数据库索引
QSqlQuery执行和操作SQL语句的方法
QSqlQueryModelSQL结果集的只读数据模型
QSqlRecord封装一个数据库的查询结果记录
QSqlRelationalTableModel单个数据库表的可编辑数据模型,具有外键支持
QSqlResult用于从特定SQL数据库访问数据的抽象接口
QSqlTableModel单个数据库表的可编辑数据模型

三、层次分割

  1. Driver 层
    它包括QSqlDriver、QSqlDriverCreator、QSqlDriverCreatorBase、QSqlDriverPlugin和QSqlResult类。
    该层提供了特定数据库和SQL API层之间的底层桥梁。更多信息请参见SQL数据库驱动程序。

  2. SQL API 层
    这些类提供对数据库的访问。使用QSqlDatabase类建立连接。通过使用QSqlQuery类实现数据库交互。除了QSqlDatabase和QSqlQuery外,支持SQL API层的还有QSqlError、QSqlField、QSqlIndex和QSqlRecord。

  3. User Interface 层
    这些类将数据库中的数据链接到数据感知小部件。它们包括QSqlQueryModel、qsqlltablemodel和QSqlRelationalTableModel。这些类是为Qt的model/view框架设计的。
    注意,在使用这些类之前,必须实例化QCoreApplication对象。

四、连接到数据库

数据库的使用一般流程即是:

  • 连接数据库 --> 数据库操作 --> 数据库关闭

在数据库操作之前,也即是 QSqlQuery 或 QSqlQueryModel 类访问数据库,需要创建并打开一个或多个数据库连接。

数据库连接通常由连接名称标识,而不是数据库名称。 这个其实和常用的数据库管理工具一样的,可以有多个连接到同一个数据库。QSqlDatabase还支持默认连接的概念,这是一个未命名的连接。在调用接受连接名称参数的QSqlQuery或QSqlQueryModel成员函数时,如果不传递连接名称,将使用默认连接。当你的应用程序只需要一个数据库连接时,创建默认连接很方便。 有时候我们就是忽略了这个默认联接就容易出问题。

注意创建连接和打开连接的区别。

创建连接涉及创建一个QSqlDatabase类的实例。连接在打开之前是不可用的。下面的代码片段展示了如何创建一个默认连接,然后打开它:

QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL");
db.setHostName("bigblue");
db.setDatabaseName("flightdb");
db.setUserName("acarlson");
db.setPassword("1uTbSbAs");
bool ok = db.open();

第一行创建connection对象,最后一行打开它以供使用。在此过程中,我们初始化一些连接信息,包括数据库名、主机名、用户名和密码。在本例中,我们连接到主机 bigblue 上的 MySQL 数据库 flightdb。addDatabase() 的"QMYSQL"参数指定连接使用的数据库驱动程序的类型。

上面代码片段中的连接将是默认连接,因为我们没有向addDatabase()传递第二个参数,即连接的名称。

例如,下面我们建立两个MySQL数据库连接,分别名为“first”和“second”:

QSqlDatabase firstDB = QSqlDatabase::addDatabase("QMYSQL", "first");
QSqlDatabase secondDB = QSqlDatabase::addDatabase("QMYSQL", "second");

初始化这些连接后,打开每个连接的open(),以建立实时连接。如果open()失败,则返回false。在这种情况下,调用QSqlDatabase::lastError() 获取错误信息。

建立连接后,可以从任何带有连接名称的地方调用静态函数 QSqlDatabase::database() ,以获得指向该数据库连接的指针。如果我们不传递连接名称,它将返回默认连接。例如:

QSqlDatabase defaultDB = QSqlDatabase::database();
QSqlDatabase firstDB = QSqlDatabase::database("first");
QSqlDatabase secondDB = QSqlDatabase::database("second");

要删除数据库连接,首先使用 QSqlDatabase::close() 关闭数据库,然后使用静态方法QSqlDatabase::removeDatabase()删除它。

Qt支持自带的数据库驱动如下表

数据库名支持数据库及版本
QDB2IBM DB2 (version 7.1 and above)
QIBASEBorland InterBase
QMYSQLMySQL (version 5.0 and above)
QOCIOracle Call Interface Driver
QODBCOpen Database Connectivity (ODBC) - Microsoft SQL Server and other ODBC-compliant databases
QPSQLPostgreSQL (versions 7.3 and above)
QSQLITE2SQLite version 2 Note: obsolete since Qt 5.14
QSQLITESQLite3 version 3
QTDSSybase Adaptive Server Note: obsolete since Qt 4.7

五、执行数据库语句

QSqlQuery类提供了一个接口,用于执行SQL语句和浏览查询的结果集。

1. 查询

要执行SQL语句,只需创建一个QSqlQuery对象并调用QSqlQuery::exec():

QSqlQuery query;
query.exec("SELECT name, salary FROM employee WHERE salary > 50000");

QSqlQuery构造函数接受一个可选的QSqlDatabase对象,该对象指定要使用哪个数据库连接。在上面的示例中,我们没有指定任何连接,因此使用默认连接。

如果发生错误,exec()返回false。这个错误可以通过QSqlQuery::lastError()得到。

2. 结果集查询

QSqlQuery提供对结果集的访问,每次访问一条记录。调用exec()之后,QSqlQuery的内部指针位于第一个记录之前的位置。我们必须调用一次QSqlQuery::next()来前进到第一个记录,然后再次调用next()来访问其他记录,直到它返回false。下面是一个按顺序遍历所有记录的典型循环:

while (query.next()) {
          QString name = query.value(0).toString();
          int salary = query.value(1).toInt();
          qDebug() << name << salary;
}

函数的作用是:返回当前记录中某个字段的值。字段被指定为从0开始的索引。QSqlQuery::value()返回一个QVariant类型,该类型可以保存各种c++和Qt核心数据类型,如int、QString和QByteArray。

不同的数据库类型会自动映射到最接近的Qt等价类型中。在上述代码片段中,我们调用QVariant::toString()和QVariant::toInt()来将变量转换为QString和int。

你可以使用QSqlQuery::next()、QSqlQuery::previous()、QSqlQuery::first()、QSqlQuery::last()和QSqlQuery::seek()在数据集中导航。当前行索引由QSqlQuery::at()返回,对于支持QSqlQuery::size()的数据库,结果集中的总行数可用QSqlQuery::size()。

要确定数据库驱动程序是否支持给定的功能,请使用QSqlDriver::hasFeature()。在下面的例子中,我们调用QSqlQuery::size()来确定底层数据库支持该特性的结果集的大小;否则,我们导航到最后一条记录,并使用查询的位置来告诉我们有多少条记录。

QSqlQuery query;
int numRows;
query.exec("SELECT name, salary FROM employee WHERE salary > 50000");

QSqlDatabase defaultDB = QSqlDatabase::database();
if (defaultDB.driver()->hasFeature(QSqlDriver::QuerySize)) {
          numRows = query.size();
} else {
          // this can be very slow
          query.last();
          numRows = query.at() + 1;
}

如果你在一个结果集中导航,并且只使用next()和seek()来浏览前向,你可以在调用exec()之前调用QSqlQuery::setForwardOnly(true)。这是一个简单的优化,在操作大型结果集时可以显著提高查询速度。

3. 插入、更新和删除记录

QSqlQuery可以执行任意SQL语句,而不仅仅是select。下面的例子使用INSERT将一条记录插入到表中:

QSqlQuery query;
query.exec("INSERT INTO employee (id, name, salary) "
                 "VALUES (1001, 'Thad Beaumont', 65000)");

如果想要同时插入多条记录,将查询语句和实际插入的值分开通常更有效。这可以使用占位符来实现。

Qt支持两种占位符语法:命名绑定(named binding)和位置绑定(position binding)。下面是命名绑定的例子:

QSqlQuery query;
query.prepare("INSERT INTO employee (id, name, salary) "
                    "VALUES (:id, :name, :salary)");
query.bindValue(":id", 1001);
query.bindValue(":name", "Thad Beaumont");
query.bindValue(":salary", 65000);
query.exec();

这是一个位置绑定的例子:

QSqlQuery query;
query.prepare("INSERT INTO employee (id, name, salary) "
                    "VALUES (?, ?, ?)");
query.addBindValue(1001);
query.addBindValue("Thad Beaumont");
query.addBindValue(65000);
query.exec();

这两种语法都适用于Qt提供的所有数据库驱动程序。如果数据库本身支持这种语法,Qt只需将查询转发给DBMS;否则,Qt通过预处理查询来模拟占位符语法。DBMS最终执行的实际查询可以通过QSqlQuery::executedQuery()获得。

插入多条记录时,只需要调用QSqlQuery::prepare()一次。然后根据需要多次调用bindValue()或addBindValue(),然后调用exec()。

除了性能之外,占位符的一个优点是可以轻松地指定任意值,而不必担心转义特殊字符。

更新一条记录类似于将它插入到表中:

QSqlQuery query;
query.exec("UPDATE employee SET salary = 70000 WHERE id = 1003");

还可以使用命名绑定或位置绑定将参数与实际值关联起来。
最后,这里有一个DELETE语句的例子:

QSqlQuery query;
query.exec("DELETE FROM employee WHERE id = 1007");

4. 事务

如果底层数据库引擎支持事务,QSqlDriver::hasFeature(QSqlDriver:: transactions)将返回true。

您可以使用QSqlDatabase::transaction()来启动一个事务,然后在事务的上下文中执行您想要执行的SQL命令,然后是QSqlDatabase::commit()或QSqlDatabase::rollback()。使用事务时,必须在创建查询之前启动事务。

例子:

QSqlDatabase::database().transaction();
QSqlQuery query;
query.exec("SELECT id FROM employee WHERE name = 'Torild Halvorsen'");
if (query.next()) {
          int employeeId = query.value(0).toInt();
          query.exec("INSERT INTO project (id, name, ownerid) "
                     "VALUES (201, 'Manhattan Project', "
                     + QString::number(employeeId) + ')');
}

QSqlDatabase::database().commit();

可以使用事务来确保复杂操作是原子的(例如,查找外键并创建记录),或者提供一种在中间取消复杂更改的方法。

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

太阳风暴

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值