Bootstrap

QT开发--QT SQL模块

第十五章 QT SQL模块

15.1 QT SQL模块概览

        Qt SQL模块是Qt框架中操作数据库的组件,提供易用API,支持SQLite、MySQL等多种数据库。它包含数据库驱动与连接功能。

15.1.1 QSqlDatabase 类

        在Qt SQL模块中,数据库驱动基于QSqlDriver类,可通过继承创建自定义驱动。

        使用QSqlDatabasestatic addDatabase()方法能创建数据库连接,需指定驱动类型连接名(非数据库名)。连接由连接名区分,支持同一数据库的多连接。默认连接是无名连接,创建时省略连接名即可。若使用静态成员函数且不指定连接名,则操作默认连接。

15.1.2. 数据库驱动与连接

        Qt SQL通过数据库驱动与各种数据库交互,驱动是Qt与数据库系统间的接口。

        Qt支持多种驱动,如QSQLITE、QMYSQL。

        要使用数据库,需建立连接,连接由QSqlDatabase类表示。

#include <QSqlDatabase>  // 引入Qt SQL数据库类  
#include <QDebug>        // 引入Qt调试输出类  
  
int main(int argc, char *argv[]) {    
    QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");  // 添加SQLite数据库驱动  
    db.setDatabaseName("example.db");              // 设置数据库文件名为example.db  
    if (!db.open()) {                           // 尝试打开数据库,若失败则输出错误信息并返回  
        qDebug() << "Error: Could not connect to database.";  
        return 1;  
    }  
  
    // 在此处进行数据库操作,例如查询、插入、更新等  
  
    db.close();    // 关闭数据库连接  
    return 0;      // 程序正常结束  
}

15.1.3 支持的数据库类型

        Qt SQL模块优点在于提供通用API,使代码大多独立于特定数据库。

        但要与特定数据库连接,需为Qt提供相应数据库驱动插件。以下是部分支持的数据库类型及驱动名称。

序号驱动名称数据库系统驱动说明
1QSQLITESQLite支持 SQLite3 数据库系统
2QMYSQLMySQL支持 MySQL 数据库系统
3QPSQLPostgreSQL支持 PostgreSQL 数据库系统
4QODBCODBC支持 ODBC 驱动,包括微软的 SQL Server
5QOCIOracle支持 Oracle 调用接口驱动
6QIBASEInterBase支持 Borland InterBase 驱动,适用于嵌入式和跨平台数据库应用
7QDB2IBM DB2支持 IBM DB2 数据库系统

        这些驱动名可以在创建 QSqlDatabase 实例时指定,例如:

QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL");

        在此例中,我们添加了QMYSQL驱动以连接MySQL数据库。

        随后,可利用Qt SQL模块中的类(例如QSqlQuery、QSqlTableModel)执行数据库操作,无需关注数据库特异性。

15.1.4 Qt SQL模块中的主要类与概念

        Qt SQL模块包含多个类,用于数据库操作:

        QSqlQuery执行SQL查询

        QSqlTableModelQSqlRelationalTableModel表示和操作数据库表数据

        QSqlQueryModel展示查询结果

        QSqlError处理错误

        QSqlRecord代表访问记录(行)

        QSqlField访问字段(列)

15.1.5 数据库操作基础

        在Qt SQL模块中,QSqlQuery类是执行SQL语句的核心工具,它支持创建表、插入记录、查询数据、更新记录、删除记录等操作。

创建表

QSqlQuery query;  
query.exec("CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, name TEXT, age INTEGER)");

插入记录

query.prepare("INSERT INTO users (name, age) VALUES (?, ?)");  
query.addBindValue("John Doe");  //按顺序绑定到sql语句占位符
query.addBindValue(30);  
query.exec();

查询数据

query.exec("SELECT * FROM users");  
while (query.next()) {  
    int id = query.value("id").toInt();  
    QString name = query.value("name").toString();  
    int age = query.value("age").toInt();  
    qDebug() << "User:" << id << name << age;  
}
​
  QSqlQuery query;
    query.prepare("SELECT * FROM users 
                WHERE username = :username 
                  AND password = :password");
    query.bindValue(":username", username);
    query.bindValue(":password", password);

        在SQL语句中,字符串值应该被单引号(')包围,而不是双引号(")。双引号在SQL中通常用于标识数据库对象(如表名、列名等),而字符串值则应该使用单引号。 

SELECT * FROM users WHERE username = '123' AND password = '123';

更新记录

query.prepare("UPDATE users SET age = ? WHERE id = ?");  
query.addBindValue(35);  
query.addBindValue(1);  
query.exec();

删除记录

query.prepare("DELETE FROM users WHERE id = ?");  
query.addBindValue(1);  
query.exec();

使用事务

QSqlDatabase db = QSqlDatabase::database();  
db.transaction();   //数据库启动事务
// 执行数据库操作...  
if (/* 操作成功 */) {  
    db.commit();  
} else {  
    db.rollback();  
}

执行存储过程

query.prepare("CALL my_stored_procedure(?, ?)");  
query.addBindValue("param1");  
query.addBindValue("param2");  
query.exec();

检查查询是否成功

if (!query.exec("SELECT * FROM users")) {  
    QSqlError error = query.lastError();  
    if (error.type() != QSqlError::NoError) {  
        qDebug() << "Error:" << error.text();  
    }  
}

获取查询结果的记录数(如果驱动支持):

int numRows = query.size(); // 可能返回-1表示不支持

如果不支持,则通过遍历计算:

int numRows = 0;  
while (query.next()) {  
    numRows++;  
}

使用QSqlRecordQSqlField处理查询结果

QSqlRecord record = query.record();  
while (query.next()) {  
    for (int i = 0; i < record.count(); ++i) {  
        QSqlField field = record.field(i);  
        qDebug() << "Field:" << field.name() << "Value:" << query.value(i);  
    }  
}

15.2 使用QSqlTableModel

        使用QSqlTableModel实例与数据库表关联并检索数据

QSqlTableModel model;  
model.setTable("users");  
model.select();  
  
// 遍历并显示数据  
//遍历行
for (int row = 0; row < model.rowCount(); ++row) {  
    //遍历列
    for (int col = 0; col < model.columnCount(); ++col) {  
        //获取行列位置的索引
        QModelIndex index = model.index(row, col);  
        qDebug() << "Row:" << row << "Col:" << col << "Value:" << model.data(index);  
    }  
}

        上例创建了一个QSqlTableModel实例,将其与users表关联,检索所有记录,并遍历显示每个单元格的值。

15.2 使用QSqlQueryModel

MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), tableView(nullptr), model(nullptr) {  
    // 初始化数据库连接  
    QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");  
    db.setHostName("localhost"); // SQLite 通常不需要主机名,但这里保留以防其他数据库  
    db.setDatabaseName("testdb.db"); // 设置数据库文件名  
    // SQLite 默认不需要用户名和密码,以下两行通常不需要  
    // db.setUserName("hebbe");   
    // db.setPassword("123456");  
  
    if (!db.open()) {  
        // 如果数据库连接失败,输出错误信息并返回  
        qWarning() << "Failed to connect to database:" << db.lastError().text();  
        return;  
    }  
  
    // 创建并设置QTableView  
    tableView = new QTableView(this);  
    setCentralWidget(tableView);  
  
    // 创建QSqlQueryModel并执行查询  
    model = new QSqlQueryModel(this);  
    model->setQuery("SELECT * FROM table1;"); // 执行查询,请确保表名正确  
  
    // 检查查询模型是否有错误  
    if (model->lastError().isValid()) {  
        // 如果有错误,输出错误信息并返回  
        qWarning() << "Query model error:" << model->lastError().text();  
        return;  
    }  
  
    // 将模型与QTableView关联  
    tableView->setModel(model);  

    /*可以验证,模型和View关联后,model改变,view自动改变*/
    //model->setQuery("SELECT * FROM table1 limit1;"); // 执行查询,请确保表名正确  
  
    // 调整列宽以显示内容  
    tableView->resizeColumnsToContents();  
  
    // 输出模型行数,验证数据加载情况  
    qDebug() << "Model row count:" << model->rowCount();  
  
    // 输出连接成功信息  
    qDebug("ok");  
}  
  
MainWindow::~MainWindow() {  
    // 析构函数,用于清理资源(当前无特殊资源需清理)  
}

15.3 使用QSqlRelationalTableModel

        使用QSqlRelationalTableModel实例与数据库表关联并设置外键关系

QSqlRelationalTableModel model;  
model.setTable("orders");  //设置模型将操作的数据库表名为"orders"
// 将orders表的user_id列与users表的id列关联,显示name列  
model.setRelation(1,                    //关联的列索引 
                QSqlRelation("users",   //关联的表名
                                "id",   //关联表的主键
                            "name"));   //关联表的关联列名
model.select();  //执行查询
  
// 遍历并显示数据  
for (int row = 0; row < model.rowCount(); ++row) {  
    for (int col = 0; col < model.columnCount(); ++col) {  
        QModelIndex index = model.index(row, col);  
        qDebug() << "Row:" << row << "Col:" << col << "Value:" << model.data(index);  
    }  
}

15.4 数据库表关系处理

        关系数据库设计中,表之间的关系至关重要,涉及引用、约束和联接。

        使用Qt SQL模块时,可以处理这些数据库表关系。

15.4.1 外键约束

        外键是数据库约束,确保数据间存在对应记录,常表现为“一对多”关系。

        在Qt SQL中,QSqlRelationalTableModel类用于处理此类外键关系

以下是一个具有外键关系的表结构示例:

users表id(主键)nameage
orders表id(主键)user_id(外键)productprice

        orders 表的 user_id 列是 users 表的 id 列的外键。

        这意味着 orders 表中的每个记录必须与 users 表中的一个记录相关联。

15.4.2 使用 QSqlRelation

        QSqlRelation 类表示两个表之间的外键关系

QSqlRelation relation("user_id", //users表的属性
                           "id", //外键表orders表的主键列名
                        "name"); //外键表中要绑定的列名

15.4.3 在 QSqlRelationalTableModel 中设置表关系

        在设置 QSqlRelationalTableModel 时,可以使用 QSqlRelation 实例设置表关系。

QSqlRelationalTableModel model;
model.setTable("orders");  //表示我要设置这个表
model.setRelation(1, QSqlRelation("users", "id", "name")); //设置外键关系
model.select(); //执行

15.4.4 使用QSqlQueryModel与Model/View框架

        QSqlQueryModel是Qt SQL模块中的类,用于处理查询结果并继承自QAbstractTableModel

        它可将SQL查询结果与视图组件关联,实现数据灵活展示。

创建并设置 QSqlQueryModel

        要使用QSqlQueryModel,先创建实例并执行SQL查询,可将此过程放在实例创建时或之后。

QSqlQueryModel model("SELECT * FROM users"); // 创建时查询  
// 或  
QSqlQueryModel model;  
model.setQuery("SELECT * FROM users"); // 创建后查询

        接着,将QSqlQueryModel视图组件(如QTableView)关联:

QTableView view;  
view.setModel(&model);  //关联视图组件和QSqlQueryModel
view.show();

        对于复杂查询,如联接,QSqlQueryModel同样适用:

QSqlQueryModel model;  
//查询,关联查询
model.setQuery("SELECT users.name, 
                    orders.product, 
                      orders.price 
                        FROM 
                    users INNER JOIN orders 
                        ON 
                    users.id = orders.user_id");  
QTableView view;          //视图组件
view.setModel(&model);    //关联视图组件和QSqlQueryModel
view.show();

悦读

道可道,非常道;名可名,非常名。 无名,天地之始,有名,万物之母。 故常无欲,以观其妙,常有欲,以观其徼。 此两者,同出而异名,同谓之玄,玄之又玄,众妙之门。

;