当前位置:   article > 正文

QT学习笔记-QtSQL

qtsql


前言

因工作需要,要实现一个小型的数据管理系统。本着想捡起来QT技能的想法,学习下QT开发界面管理数据库的操作。


一、QtSQL简介

QtSQL模块实现了对数据库的访问,Qt SQL提供了三个不同层次的API供开发者使用。包括驱动层,SQL API层,用户接口层。

层次描述
驱动层实现了特定数据库与SQL接口的底层桥接,包括的支持类有QSqlDriver、QSqlDriverCreator、QSqlDriverCreatorBase、QSqlDriverPlugin和QSqlResult
SQL API层QSqlDataBase类提供了数据库访问接口、数据库连接操作;QSqlQuery类提供了与数据库交互的操作,其他支持类还包括QSqlError、QSqlField、QSqlTableModel和QSqlRecord
用户接口层提供从数据库数据到用于数据表示的窗体的映射,包括的支持类有QSqlQueryModel、QSqlTableModel和QSqlRelationalTableModel,这些类均依据Qt的模型/视图结构设计

使用该模块需要以下两个步骤:

  1. 在项目文件即pro文件中添加如下行
QT += sql 
  • 1
  1. 在使用该模块的头文件中添加如下行
#include <QtSql>
  • 1

二、SQLite简介

关系型数据库多种多样,常见的就是甲骨文的ORacle和微软的SQL Server,还有开源的MySQL。这些用在小型数据库管理上有点奢侈和臃肿。
Qt提供了一种进程内数据库SQLite。无需安装,轻量级的。也支持视图、触发器和事务,支持嵌套SQL功能。

三、QtSQL使用

3.1建立数据库连接

在进行数据库操作之前,必须首先建立与数据库的连接。数据库通信通常是由连接名称分辨而不是数据库名称。我们可以针对同一个数据库建立多个连接。QSqlDataBase类支持创建默认连接,它是没有名称的。如下是一段创建并打开默认连接的代码

     QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
     db.setHostName("bigblue");
     db.setDatabaseName("flightdb");
     db.setUserName("acarlson");
     db.setPassword("1uTbSbAs");
     bool ok = db.open();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

如上段代码所示,创建数据库连接仅仅是实例化了一个QSqlDatabase类的对象,想要使用它得调用open函数来打开它。静态函数addDatabase原型如下:

 QSqlDatabase::addDatabase(
 const QString &type, 
 const QString &connectionName = QLatin1String(defaultConnection)
 )
  • 1
  • 2
  • 3
  • 4

参数type为驱动名,可以指定连接到哪些数据库;参数connectionname则为上述的连接名称,如未指定,则使用默认连接名,后续可直接使用不带参数的相关函数。QT支持的驱动如下:

Driver nameDBMS
QDB2IBM DB2 (version 7.1 and above)
QIBASEBorland InterBase
QMYSQLMySQL
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
QSQLITESQLite version 3

打开数据库连接后我们就可以通过相关函数来操作数据库,在使用完毕后可通过下述两个函数来关闭移除数据库

 QSqlDatabase::close()
 QSqlDatabase::removeDatabase()
  • 1
  • 2

3.2执行SQL语句

QSqlQuery类提供了一个执行SQL语句的接口并且可以遍历执行的返回结果集。数据库连接建立后就可以使用该类执行底层数据库支持的SQL语句,此方法所要做的仅是创建一个该类实例对象,然后再调用该类的exec()函数。如下:

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

3.1.1遍历结果集

QSqlQuery类提供了一个获取记录的接口,在调用exec函数后,QSqlQuery类的内部指针指向第一条记录前的位置,我们必须调用一次QSqlQuery::next()函数来获取第一条记录的位置。然后再重复调用next函数,直到返回错误。

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

QSqlQuery::value()函数返回当前记录某个属性值。 Fields 是从0开始的索引。 我们可以通过 QSqlQuery::at()获取当前记录的行索引,通过QSqlQuery::size() 获取记录的总数,即行数。
QSqlQuery::value()的返回值是 QVariant类型, 该类型可以转换为多种 C++ and core Qt数据类型,如 int, QString, 和 QByteArray.不同的数据库类型自动映射到相近的Qt类型。

QSQLITE SQLite version 3 Data Types

QSQLITE SQLite version 3 data typeSQL type descriptionRecommended input (C++ or Qt data type)
NULLNULL value.NULL
INTEGERSigned integer, stored in 8, 16, 24, 32, 48, or 64-bits depending on the magnitude of the value.typedef qint8/16/32/64
REAL64-bit floating point value.By default mapping to QString
TEXTCharacter string (UTF-8, UTF-16BE or UTF-16-LE).Mapped to QString
CLOBCharacter large string objectMapped to QString
BLOBThe value is a BLOB of data, stored exactly as it was input.Mapped to QByteArray

3.1.2增加、更新和删除记录

QSqlQuery可以执行多种SQL语句。不止select,如insert,update,delete。

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

插入多个记录可以使用占位符操作,Qt支持两种占位符语法:有名占位和定位占位。分别为
有名占位即Oracle语法

     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();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

定位占位即ODBC语法

     QSqlQuery query;
     query.prepare("INSERT INTO employee (id, name, salary) "
                   "VALUES (?, ?, ?)");
     query.addBindValue(1001);
     query.addBindValue("Thad Beaumont");
     query.addBindValue(65000);
     query.exec();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
2.update
     QSqlQuery query;
     query.exec("UPDATE employee SET salary = 70000 WHERE id = 1003");
  • 1
  • 2
3.delete
     QSqlQuery query;
     query.exec("DELETE FROM employee WHERE id = 1007"); 
  • 1
  • 2

3.1.3事务操作

事务可以用来确保复杂的操作是原子的(例如,查找外键并创建记录),或者提供一种消除中间复杂变化的方法。
可以使用QSQLDABASE::transaction()启动事务,然后是要在事务上下文中执行的SQL命令,最后是QSQLDABASE::commit()或QSQLDABASE::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();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

3.3SQL 模型类

Qt同时也在用户接口层提供了三个模型类来对数据库进行操作,QSqlQueryModel、QSqlTableModel和QSqlRelationalTableModel。这三个类都继承自 QAbstractTableModel ,因此可以很方便的将数据通过QListView和QTableView展示在UI界面内;此外基于模型/视图结构,我们也可以很方便的在不改动代码的情况下更换数据源。

QSqlQueryModel

提供了一个基于SQL查询的只读模型

     QSqlQueryModel model;
     model.setQuery("SELECT * FROM employee");

     for (int i = 0; i < model.rowCount(); ++i) {
         int id = model.record(i).value("id").toInt();
         QString name = model.record(i).value("name").toString();
         qDebug() << id << name;
     }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

QSqlTableModel

提供了一个基于单张SQL表的可读写模型

     QSqlTableModel model;
     model.setTable("employee");
     model.setFilter("salary > 50000");
     model.setSort(2, Qt::DescendingOrder);
     model.select();

     for (int i = 0; i < model.rowCount(); ++i) {
         QString name = model.record(i).value("name").toString();
         int salary = model.record(i).value("salary").toInt();
         qDebug() << name << salary;
     }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

使用该模型,可以替代写SQL语句来操作,如我们可以通过record()来或者表中的一行记录,通过setRecord()修改记录。在模型上的所有修改完成后,使用submitall或者submit来进行提交,更新数据库。

     for (int i = 0; i < model.rowCount(); ++i) {
         QSqlRecord record = model.record(i);
         double salary = record.value("salary").toInt();
         salary *= 1.1;
         record.setValue("salary", salary);
         model.setRecord(i, record);
     }
     model.submitAll();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

设置编辑策略
编辑策略表示当用户在视图进行的数据修改是否完全应用到数据库。 取值范围有

常量描述
QSqlTableModel::OnFieldChange0所有对模型的更改都会立即在数据库内更新
QSqlTableModel::OnRowChange1当前行的修改在用户选择另一不同行时生效
QSqlTableModel::OnManualSubmit2所有修改暂存在模型中,直到调用submitAll()或者revertAll()
model->setEditStrategy(QSqlTableModel::OnManualSubmit);
  • 1

QSqlRelationalTableModel

基于QSqlTableModel的扩展,支持外键。

3.4通过视图展示数据

QSqlQueryModel、QSqlTableModel和QSqlRelationalTableModel类均可以作为数据源在Qt的视图类中表示,如QListView、QTableView和QTreeView等视图类。其中,最常用的是QTableView,因该视图最适合表示二维的SQL操作结果。
如果模型是可读写的,视图将使用户可以编辑字段,我们可以通过如下调用禁止编辑。

     view->setEditTriggers(QAbstractItemView::NoEditTriggers);
  • 1

我们可以将一个模型用于多个视图,当在某一视图中更新编辑了模型后,其他视图将随即更新。
使用模型的插入行和删除行操作时,会在视图上进行特殊标注,直到进行提交。
视图类可以显示一个水平表头和一个垂直表头。水平表头在每一列之上显示一个列名,默认情况下,列名就是数据库表的字段名,可以通过setHeaderData()函数修改列名。垂直表头在每一行的最左侧显示本行的行号。

     model->setHeaderData(0, Qt::Horizontal, QObject::tr("ID"));
     model->setHeaderData(1, Qt::Horizontal, QObject::tr("Name"));
     model->setHeaderData(2, Qt::Horizontal, QObject::tr("City"));
     model->setHeaderData(3, Qt::Horizontal, QObject::tr("Country"));
  • 1
  • 2
  • 3
  • 4
创建数据感知表单

在某些时候,我们想通过一个表单来获取和更新数据库表中特定行或列的数据,这时候可以使用 QDataWidgetMapper类,具体可参考官方的BOOKS例子。暂时还没用上这个功能。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Gausst松鼠会/article/detail/652706
推荐阅读