QT SQL

数据库相关类

类名描述
QSqlDatabase代表一个数据库链接
QSqlDriverCreator为特定的驱动类型提供SQL驱动的模板工厂类
QSqlDriverCreatorBaseQSqlDriverCreator的基类
QSqlDriver用于访问特定SQL数据库的抽象基类
QSqlErrorSQL 数据库错误信息
QSqlField操作SQL数据库表和视图中的字段
QSqlIndex操作和描述数据库索引
QSqlQuery执行和操作SQL语句
QSqlRecord封装数据库记录
QSqlResult用于从特定SQL数据库访问数据的抽象界面
QSql包含整个Qt SQL模块中使用的标识符
QSqlQueryModelSQL结果集的只读数据模型
QSqlRelationalTableModel用于单个数据库表的可编辑数据模型,具有外键支持
QSqlTableModel单个数据库表的可编辑数据模型

数据库相关类分为三个层次:

  • 驱动层:
    QSqlDriver,QSqlDriverCreator,QSqlDriverCreatorBase,QSqlDriverPlugin,QSqlResult.此层次为特定数据库和SQL API之间提供了低级的沟通桥梁.
  • SQL API层:
    QSqlDatabase,QSqlQuery,QSqlError,QSqlField,QSqlIndex,QSqlRecord.此层此提供对数据库的访问.
  • 用户界面层:
    QSqlQueryModel, QSqlTableModel, QSqlRelationalTableModel.此层次将数据从数据库显示在widget上,要配合Qt的 model/view框架使用.

连接到数据库

在访问数据库之前需要先创建并打开一个或多个数据库链接.数据库链接由链接名称来区分,不由数据库名称区分.同一个数据库上可以有多个数据库链接.
注意创建链接和打开链接的区别:创建链接涉及到QSqlDatabase的实例化.连接在打开之前是不可用的,需要调用open()函数来打开它.

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

第一句创建链接,最后一句打开链接,中间语句设置链接的各种参数,包括主机名,数据库名,数据库用户名,数据库密码等.第一句中的参数”QMYSQL”指明我们使用MySQL数据库,链接名称为空(默认链接).
如果发生错误请使用QSqlDatabase::lastError()来获取错误信息.
使用QSqlDatabase::database()来获取已经创建的链接.
要删除一个数据库链接,先调用close()再调用removeDatabase().

SQL数据库驱动

Qt SQL模块使用驱动插件来和不同的数据库API进行通讯.因为Qt SQL模块API是”数据库独立的”,所有的数据库特异化操作代码都被包含在各自对应的驱动中.Qt SQL模块已经支持一些驱动了,并且你也可以自己添加数据库驱动.下表为已经支持的驱动:

驱动名称描述
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
QTDSSybase Adaptive Server Note: obsolete from Qt 4.7

执行SQL语句

QSqlQuery类为执行SQL语句和遍历执行结果集提供了接口.

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

QSqlQuery的构造函数可以接收一个QSqlDatabase对象,以此来指定SQL语句要使用的数据库链接.如果没有提供QSqlDatabase对象,SQL语句会在默认链接上执行.如果有错误exec()函数会返回fasle.使用QSqlQuery::laseError()获取错误信息.

遍历结果集合:

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;
 }

QSqlQuery::value() 返回当前记录中的字段值,返回值是QVariant类型的.
结果集合遍历函数列表:

函数名称描述
QSqlQuery::next()下一条记录
QSqlQuery::previous()上一条记录
QSqlQuery::first()第一条记录
QSqlQuery::last()最后一条记录
QSqlQuery::seek()跳到指定记录
QSqlQuery::at()当前记录索引
QSqlQuery::size()总记录条数
QSqlDriver::hasFeature()当前类型的数据库是否支持某种操作特性
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
{
    query.last();
    numRows = query.at()+1;
}

如果仅使用next()和seek()的正值进行迭代,则可以在调用exec()之前调用QSqlQuery :: setForwardOnly(true). 这是一个简单的优化,可以加快大型结果集上的查询速度。

插入,更新,删除记录

QSqlQuery可执行任意的SQL语句,而不止SELECT语句.

插入示例

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

如果希望插入多条记录,将SQL语句和实际要插入的值分开来写是更高效的,这可以使用占位符来实现,Qt支持两种格式的占位符,名称绑定和位置绑定.

  • 名称绑定示例
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执行的SQL语句可以通过QSqlQuery::ecutQuery()获取.
插入多条记录时只需要调用一次QSqlQuery::prepare(),然后可以按照你的需要重复多次调用bindValue()或者addBindValue() 和exec().

更新示例

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

同样,更新时也可以使用名称或者位置占位符.

删除示例

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

判断表是否存在

bool isTableExists(QString tableName)
{
      QSqlDatabase db = QSqlDatabase::database();          // 假设数据库连接已经成功打开
      QStringList tableList = db.tables(QSql::AllTables);
      return tableList.contains(tableName);
}

数据库事务

如果底层数据库引擎支持事务,QSqlDriver::hasFeature(QSqlDriver::Transactions)会返回true.调用QSqlDatabase::transaction()来启动事务,后面跟着你想在事务上下文中完成的SQL语句,然后执行QSqlDatabase::commit()或者QSqlDatabase::rollback().使用事务时必须要在创建query前开启事务.

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();

事务用于保证复杂的操作的原子性.

使用SQL模型类

除了QSqlQuery之外,Qt提供三个高级类来访问数据库:

类名描述
QSqlQueryModel基于任意SQL查询的只读模型
QSqlTableModel单独一张表上的读写模型
QSqlRelationalTableModel具有外键支持的QSqlTableModel

这些类继承自QAbstractTableModel(进一步继承自QAbstractItemModel),这使得在诸如QListView和QTableView视图类中呈现数据库中的数据变得简单.

    原文作者:MayBeZH
    原文地址: https://www.jianshu.com/p/a06d3511e53f
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞