小言_互联网的博客

Qt扫盲-数据库编程综述

511人阅读  评论(0)

一、概述

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驱动程序工厂的模板类
QSqlDriverCreatorBase SQL驱动程序工厂的基类
QSqlError SQL数据库错误信息
QSqlField 操作SQL数据库表和视图中的字段
QSqlIndex 操作和描述数据库索引
QSqlQuery 执行和操作SQL语句的方法
QSqlQueryModel SQL结果集的只读数据模型
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支持自带的数据库驱动如下表

数据库名 支持数据库及版本
QDB2 IBM DB2 (version 7.1 and above)
QIBASE Borland InterBase
QMYSQL MySQL (version 5.0 and above)
QOCI Oracle Call Interface Driver
QODBC Open Database Connectivity (ODBC) - Microsoft SQL Server and other ODBC-compliant databases
QPSQL PostgreSQL (versions 7.3 and above)
QSQLITE2 SQLite version 2 Note: obsolete since Qt 5.14
QSQLITE SQLite3 version 3
QTDS Sybase 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();

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


转载:https://blog.csdn.net/qq_43680827/article/details/128766565
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场