超详细Qt中如何使用数据库——附赠代码和实际例子_qt 在开发板上使用数据库,怎么操作-程序员宅基地

技术标签: qt  oracle  GUI编程之Qt  数据库  

0 什么情况需要数据库

使用一个东西务必是有原因。那为什么使用数据库?

  • 1 大规模的数据需要处理(比如上千上万的数据量)
  • 2 需要把数据信息存储起来,无论是本地还是服务上,而不是断电后数据信息就消失了。

如果不是上面的原因化,一般可以使用数组来处理。

1 Qt使用数据库

  • 1 .pro文件中添加 QT+=sql
  • 2 单独建立一个头文件来处理数据库连接,如建立头文件
#ifndef CONNECTION_H
#define CONNECTION_H

#include <QMessageBox>
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QDebug>

static bool createConnection(){
    
    //连接第一个数据库
    //QMYSQL
    QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL", "connection1");//需要使用的数据库驱动和联检建立的名称(方便建立多个数据库连接【使用不同的数据库时】区分)
    db.setHostName("127.0.0.1");//连接地址
    db.setUserName("root");//数据库账户
    db.setPassword("root");//密码
    db.setPort(8889);//端口
    //test_majiang.db
    db.setDatabaseName("test_majiang");//需要用到的数据库

    if (!db.open()) {
    //如果数据库连接失败,则弹出
        //critical(QWidget *parent, const QString &title,
        //const QString &text,
        //QMessageBox::StandardButtons buttons = Ok,
        //QMessageBox::StandardButton defaultButton = NoButton)
           QMessageBox::critical(0, "Cannot open database",
                                 "Unable to establish a database connection", QMessageBox::Cancel);
           return false;
       }

    return true;
}

#endif // CONNECTION_H

如果需要移除一个数据库连接,可以使用。

 QSqlDatabase::close();//关闭数据库
 QSqlDatabase::removeDatabase();//移除该连接

一般常使用的数据库驱动是MYSQL和QSQLITE。二者区别在于,前者用于服务器存储信息,后者用于本地存储信息。并且QSQLITE主要用于嵌入式,占用资源非常低,占用内存小,通常几百k就搞定。

2 使用数据库

连接上数据库一般就是使用数据库,进行对数据库的增删改查。
这里有三种方法。

2.1 使用QSqlQuery

头文件

#include "connection.h"
#include <QVariant>
#include <QSqlDriver>
#include <QSqlRecord>
#include <QSqlField>
#include <QSqlError>

2.1.1 使用数据库前的准备:

    //创建数据库连接
    if(!createConnection()) return 1;//返回情况可以替换,视不同情况而定
	//指定某个数据库连接
    QSqlDatabase db2 = QSqlDatabase::database("connection1");

2.1.2 开始对数据进行操作:

首先创建QSqlQuery 对象,然后进行操作。

    QSqlDatabase db2 = QSqlDatabase::database("connection2");
    QSqlQuery query2(db2);

2.1.3 进行创表和插入值:

   // qDebug() << "connection2:";
   //创建表,并插入值
       query2.exec("create table student (id int primary key,"
               "name varchar(20))");
    query2.exec("insert into student values(0, 'Mike')");
    query2.exec("insert into student values(1, 'Lili')");
    query2.exec("insert into student values(2, 'Jame')");

2.1.4 批量处理

上面的单条在这里插入代码片插入语句明显比较麻烦,可以使用批量插入数据:

    query2.exec("insert into student(id,name) values(3,'Qinsong')");//单挑操作

    //名称绑定
    query2.prepare("insert into student(id, name) values(:id, :name)");
    int idValue = 4;
    QString nameValue = "Songjiang";
    query2.bindValue(":id", idValue);//绑定数据
    query2.bindValue(":name", nameValue);
    query2.exec();//执行

    //位置绑定
    query2.prepare("insert into student(id, name) values(?, ?)");
    int idValue2 = 5;
    QString nameValue2 = "LingChong";
    query2.addBindValue(idValue2);//绑定数据
    query2.addBindValue(nameValue2);
    if(!query2.execBatch()) qDebug() <<"位置绑定:" <<query2.lastError() <<endl;//如果执行不成功执行

    //批量处理
    query2.prepare("insert into student(id, name) values(?,?)");
    QVariantList ids;
    ids << 6 << 7 << 8;
    query2.addBindValue(ids);
    QVariantList names;
    names << "Qinghua" << "Nanda" << "Zhongkeda";
    query2.addBindValue(names);
    if(!query2.execBatch()) qDebug() << query2.lastError()<< endl;

2.1.5 进行查询并输出查询结果:

    query2.exec("select * from student");//执行sql语句
    while(query2.next()){
    
        qDebug()<< query2.value(0).toInt() << query2.value(1).toString();
    }

2.1.6 查看数据驱动支持特性

查看当前数据库是否是支持某特性,比如当前记录的索引数(即结果条数):

    int numRows;
    if(db2.driver()->hasFeature(QSqlDriver::QuerySize)){
    //是否该特性
        qDebug()<< "has feature:query size";
        numRows = query2.size();
    }else{
    
        qDebug() << "no feature:query size";
        query2.last();
        numRows = query2.at() + 1;//使用at,需要之前使用quey2.next()遍历所有select搜索后的结果,而使用query2.size()则不需要
    }
    
    //此处执行上面的查询操作,下面的操作才有意义
    qDebug() << "row number: " << numRows;
    //指向索引为1的记录,即第二条记录
    query2.seek(1);
    //返回当前索引值
    qDebug() << "current index:" << query2.at();
    //获得当前行的记录
    QSqlRecord record = query2.record();

    //获得记录中"id"和"name"两个字段的值
    int id = record.value("id").toInt();
    QString name = record.value("name").toString();
    qDebug() <<"id" << id << "name:" <<name;

    //获得索引为1的字段,即第二个字段
    QSqlField field = record.field(1);

    //输出字段名和字段值,结果为"name"和"MaLiang"
    qDebug() << "second field:" << field.name()
             << "field value:" << field.value().toString();

2.1.7 事务(使数据操作变为原子性)

如果中间有一步sql操作执行出错,则全部sql操作都不执行。

    QSqlDatabase db2 = QSqlDatabase::database("connection2");
    QSqlDatabase::database().transaction();//开始(类似于mutex线程锁)
    QSqlQuery query(db2);//此语句必须在上面一条语句的后面
    //执行sql操作
    QSqlDatabase::database().commit();//结束

2.2 使用QSqlQueryModel查询模型

优势:

  • 这是基于sql查询的只读模型,编写sql语句变得容易。

文件头:

#include <QSqlQueryModel>
  QSqlDatabase db = QSqlDatabase::database("connection1");

    QSqlQueryModel *model = new QSqlQueryModel(this);


    model->setQuery("select * from student", db);
    model->setHeaderData(0, Qt::Horizontal, tr("学号"));
    model->setHeaderData(1, Qt::Horizontal, tr("姓名"));
    model->setHeaderData(2, Qt::Horizontal, tr("课程"));

    QTableView *view = new QTableView(this);
    view->setModel(model);

    setCentralWidget(view);

2.3 使用QSqlTableModel表格模型

先上结果:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
优势:

  • 编译的代码很容易适应其他的数据源,例如后面如果要使用xml文件来存储数据,只需要更换数据模型。
  • 提供了一次只能操作一个sql表的读/写模型,可以浏览和修改独立的sql表,并且只需编写很少的代码,无需了解sql语句。

2.3.1 准备

头文件:

#include <QSqlTableModel>
    QSqlTableModel* model;//创建对象指针

2.3.2 进行操作:

    QSqlDatabase db = QSqlDatabase::database("connection1");
    model = new QSqlTableModel(this, db);//由于在窗口的类中创建对象,因此实例化对象时,使用this指针(指向操作函数的指针)作为父对象

    model->setTable("student");
    model->select();//执行
    //设置编辑策略
    model->setEditStrategy(QSqlTableModel::OnManualSubmit);//对所有模型改变立即用到数据库
    ui->tableView->setModel(model);

常见操作:

// 提交修改按钮
void MainWindow::on_pushButton_clicked()
{
    
    // 开始事务操作
    model->database().transaction();
    if (model->submitAll()) {
    
        if(model->database().commit()) // 提交
            QMessageBox::information(this, tr("tableModel"),
                                     tr("数据修改成功!"));
    } else {
    
        model->database().rollback(); // 回滚
        QMessageBox::warning(this, tr("tableModel"),
                             tr("数据库错误: %1").arg(model->lastError().text()),
                             QMessageBox::Ok);
    }
}

// 撤销修改按钮
void MainWindow::on_pushButton_2_clicked()
{
    
    model->revertAll();
}

// 查询按钮,进行筛选
void MainWindow::on_pushButton_5_clicked()
{
    
    QString name = ui->lineEdit->text();

    // 根据姓名进行筛选,一定要使用单引号
    model->setFilter(QString("name = '%1'").arg(name));
    model->select();
}

// 显示全表按钮
void MainWindow::on_pushButton_6_clicked()
{
    
    model->setTable("student");
    model->select();
}

// 按id升序排列按钮
void MainWindow::on_pushButton_7_clicked()
{
    
    //id字段,即第0列,升序排列
    model->setSort(0, Qt::AscendingOrder);
    model->select();

}

// 按id降序排列按钮
void MainWindow::on_pushButton_8_clicked()
{
    
    model->setSort(0, Qt::DescendingOrder);
    model->select();

}
// 删除选中行按钮
void MainWindow::on_pushButton_4_clicked()
{
    
    // 获取选中的行
    int curRow = ui->tableView->currentIndex().row();

    // 删除该行
    model->removeRow(curRow);
    int ok = QMessageBox::warning(this,tr("删除当前行!"),
                                  tr("你确定删除当前行吗?"), QMessageBox::Yes, QMessageBox::No);
    if(ok == QMessageBox::No)
    {
     // 如果不删除,则撤销
        model->revertAll();
    } else {
     // 否则提交,在数据库中删除该行
        model->submitAll();
    }

}
// 添加记录按钮
void MainWindow::on_pushButton_3_clicked()
{
    
    // 获得表的行数
    int rowNum = model->rowCount();
    int id = 10;

    // 添加一行
    model->insertRow(rowNum);
    model->setData(model->index(rowNum, 0), id);

    // 可以直接提交
    //model->submitAll();
}

2.4 使用QSqlRelationalTableModel

先上结果:
在这里插入图片描述

优势:

  • 1 在QSqlTableModel基础上提供了对外键(一个表的一字字段和另一个表中的主键字段之间的映射)的支持。
    文件头:
#include <QSqlRelationalTableModel>

操作:

    QSqlDatabase db = QSqlDatabase::database("connection1");
    QSqlRelationalTableModel* model = new QSqlRelationalTableModel(this, db);

   model->setTable("student");
   model->setRelation(2, QSqlRelation("course","id","name"));
   model->select();

   QTableView* view = new QTableView(this);
   view->setModel(model);
   setCentralWidget(view);
   view->setItemDelegate(new QSqlRelationalDelegate(view));

3 实际应用(登陆)

先上结果:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
谈起使用数据库,对于新手来说,最常见的就是实现登陆账户密码的登陆。

3.1 连接数据库

#ifndef CONNECTION_H
#define CONNECTION_H

#include <QMessageBox>
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QDebug>

static bool createConnection(){
    


    //连接第一个数据库
    //QMYSQL
    QSqlDatabase db2 = QSqlDatabase::addDatabase("QMYSQL", "connection1");
    db2.setHostName("127.0.0.1");
    db2.setUserName("root");
    db2.setPassword("root");
    db2.setPort(8889);
    //test_majiang.db
    db2.setDatabaseName("test_majiang");

    if (!db2.open()) {
    
        //critical(QWidget *parent, const QString &title,
        //const QString &text,
        //QMessageBox::StandardButtons buttons = Ok,
        //QMessageBox::StandardButton defaultButton = NoButton)
           QMessageBox::critical(0, "Cannot open database",
                                 "Unable to establish a database connection", QMessageBox::Cancel);
           return false;
       }

    return true;
}

#endif // CONNECTION_H

3.2 登陆

一般登陆界面都使用QDialog窗口,为什么呢?
QWidget类是所有用户界面对象的基类。 窗口部件是用户界面的一个原子:它从窗口系统接收鼠标、键盘和其它事件,并且在屏幕上绘制自己的表现。每一个窗口部件都是矩形,并且它们按Z轴顺序排列的。一个窗口部件可以被它的父窗口部件或者它前面的窗口部件盖住一部分。

QMainWindow 类提供一个有菜单条、锚接窗口(例如工具条)和一个状态条的主应用程序窗口。主窗口通常用在提供一个大的中央窗口部件(例如文本编辑或者绘制画布)以及周围菜单、工具条和一个状态条。QMainWindow常常被继承,因为这使得封装中央部件、菜单和工具条以及窗口状态变得更容易。继承使创建当用户点击菜单项或者工具条按钮时被调用的槽成为可能。你也可以使用Qt设计器来创建主窗口。

QDialog类是对话框窗口的基类。对话框窗口是主要用于短期任务以及和用户进行简要通讯的顶级窗口。QDialog可以是模式的也可以是非模式的。QDialog支持扩展性并且可以提供返回值。它们可以有默认按钮。QDialog也可以有一个QSizeGrip在它的右下角,使用setSizeGripEnabled()。

QDialog 是最普通的顶级窗口。不被嵌入到一个父窗口部件的窗口部件被叫做顶级窗口部件。通常情况下,顶级窗口部件是有框架和标题栏的窗口(尽管如果使用了一定的窗口部件标记,创建顶级窗口部件时也可能没有这些装饰。)在Qt中,QMainWindow和和不同的QDialog的子类是最普通的顶级窗口。

如果是顶级对话框,那就基于QDialog创建,如果是主窗体,那就基于QMainWindow,如果不确定,或者有可能作为顶级窗体,或有可能嵌入到其他窗体中,则基于QWidget创建。当然了,实际中,你还可以基于任何其他部件类来派生。看实际需求了,比如QFrame、QStackedWidget等等。

此处参考:原文链接:https://blog.csdn.net/ikahn/article/details/6706284

QDialog窗口类的cpp编码:

#include "login.h"
#include "ui_login.h"

#include "connection.h"
#include <QMessageBox>
#include <QDebug>
#include <QWidget>
#include <QStackedWidget>
#include <QSqlError>

Login::Login(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Login)
{
    
    ui->setupUi(this);

    ui->passwordLineEdit->setEchoMode(QLineEdit::Password);

//设置窗体背景
    QPalette palette;   
 palette.setBrush(QPalette::Background,QBrush(QPixmap(":/img/img1.png").scaled(this->size())));//自适应窗口大小
    this->setPalette(palette);
    this->setWindowTitle("测试登陆界面");

}

Login::~Login()
{
    
    delete ui;
}
//登陆按钮逻辑
void Login::on_loginButton_clicked()
{
    
    QString name = ui->accountLineEdit->text();
    QString password = ui->passwordLineEdit->text();
    if(name.isEmpty()){
    
        QMessageBox::information(this, tr("请输入账号"),tr("请先输入账号再登陆,谢谢!"),
                                 QMessageBox::Ok);
        ui->accountLineEdit->setFocus();
    }else if(password.isEmpty()){
    
        QMessageBox::information(this, tr("请输入密码"),tr("请先输入密码再登陆,谢谢!"),
                                 QMessageBox::Ok);
        ui->passwordLineEdit->setFocus();
    }else{
    
         if(!createConnection()){
    
             QMessageBox::information(this, tr("提示"),tr("请先连接网络,谢谢!"),
                                      QMessageBox::Ok);
         }else{
    
             QSqlDatabase db = QSqlDatabase::database("connection1");
             QSqlQuery query(db);

             QString str = QString("select * from user where account = '%0' and password = '%1'").arg(name).arg(password);
             query.exec(str);
             int record = query.size();
             qDebug() << "record:" << record<< endl;

//             while(query.next()){
    
//                   qDebug() << query.value(0).toInt() <<query.value(1).toInt()
//                                      <<query.value(2).toString() <<query.value(3).toString();
//              }

             //未连接上数据库返回-1,连接上查询失败返回0,查到返回1
             if(record == -1 || record == 0){
    
                  QMessageBox::information(this,tr("提示"),tr("用户名或密码错误!"),QMessageBox::Ok);
                  ui->passwordLineEdit->clear();
                  ui->passwordLineEdit->setFocus();
             }else{
    
                 QMessageBox::information(this,tr("提示"),tr("登陆成功!"),QMessageBox::Ok);
                 QDialog::accept();
             }

         }
     }
}

主函数:

#include "mywidget.h"

#include <QApplication>

#include "login.h"

int main(int argc, char *argv[])
{
    
    QApplication a(argc, argv);
    MyWidget w;

    Login dlg;
    if (dlg.exec() == QDialog::Accepted) {
    
        w.show();
        return a.exec();
    } else {
    
        return 0;
    }
}

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_33375598/article/details/105565251

智能推荐

oracle 12c 集群安装后的检查_12c查看crs状态-程序员宅基地

文章浏览阅读1.6k次。安装配置gi、安装数据库软件、dbca建库见下:http://blog.csdn.net/kadwf123/article/details/784299611、检查集群节点及状态:[root@rac2 ~]# olsnodes -srac1 Activerac2 Activerac3 Activerac4 Active[root@rac2 ~]_12c查看crs状态

解决jupyter notebook无法找到虚拟环境的问题_jupyter没有pytorch环境-程序员宅基地

文章浏览阅读1.3w次,点赞45次,收藏99次。我个人用的是anaconda3的一个python集成环境,自带jupyter notebook,但在我打开jupyter notebook界面后,却找不到对应的虚拟环境,原来是jupyter notebook只是通用于下载anaconda时自带的环境,其他环境要想使用必须手动下载一些库:1.首先进入到自己创建的虚拟环境(pytorch是虚拟环境的名字)activate pytorch2.在该环境下下载这个库conda install ipykernelconda install nb__jupyter没有pytorch环境

国内安装scoop的保姆教程_scoop-cn-程序员宅基地

文章浏览阅读5.2k次,点赞19次,收藏28次。选择scoop纯属意外,也是无奈,因为电脑用户被锁了管理员权限,所有exe安装程序都无法安装,只可以用绿色软件,最后被我发现scoop,省去了到处下载XXX绿色版的烦恼,当然scoop里需要管理员权限的软件也跟我无缘了(譬如everything)。推荐添加dorado这个bucket镜像,里面很多中文软件,但是部分国外的软件下载地址在github,可能无法下载。以上两个是官方bucket的国内镜像,所有软件建议优先从这里下载。上面可以看到很多bucket以及软件数。如果官网登陆不了可以试一下以下方式。_scoop-cn

Element ui colorpicker在Vue中的使用_vue el-color-picker-程序员宅基地

文章浏览阅读4.5k次,点赞2次,收藏3次。首先要有一个color-picker组件 <el-color-picker v-model="headcolor"></el-color-picker>在data里面data() { return {headcolor: ’ #278add ’ //这里可以选择一个默认的颜色} }然后在你想要改变颜色的地方用v-bind绑定就好了,例如:这里的:sty..._vue el-color-picker

迅为iTOP-4412精英版之烧写内核移植后的镜像_exynos 4412 刷机-程序员宅基地

文章浏览阅读640次。基于芯片日益增长的问题,所以内核开发者们引入了新的方法,就是在内核中只保留函数,而数据则不包含,由用户(应用程序员)自己把数据按照规定的格式编写,并放在约定的地方,为了不占用过多的内存,还要求数据以根精简的方式编写。boot启动时,传参给内核,告诉内核设备树文件和kernel的位置,内核启动时根据地址去找到设备树文件,再利用专用的编译器去反编译dtb文件,将dtb还原成数据结构,以供驱动的函数去调用。firmware是三星的一个固件的设备信息,因为找不到固件,所以内核启动不成功。_exynos 4412 刷机

Linux系统配置jdk_linux配置jdk-程序员宅基地

文章浏览阅读2w次,点赞24次,收藏42次。Linux系统配置jdkLinux学习教程,Linux入门教程(超详细)_linux配置jdk

随便推点

matlab(4):特殊符号的输入_matlab微米怎么输入-程序员宅基地

文章浏览阅读3.3k次,点赞5次,收藏19次。xlabel('\delta');ylabel('AUC');具体符号的对照表参照下图:_matlab微米怎么输入

C语言程序设计-文件(打开与关闭、顺序、二进制读写)-程序员宅基地

文章浏览阅读119次。顺序读写指的是按照文件中数据的顺序进行读取或写入。对于文本文件,可以使用fgets、fputs、fscanf、fprintf等函数进行顺序读写。在C语言中,对文件的操作通常涉及文件的打开、读写以及关闭。文件的打开使用fopen函数,而关闭则使用fclose函数。在C语言中,可以使用fread和fwrite函数进行二进制读写。‍ Biaoge 于2024-03-09 23:51发布 阅读量:7 ️文章类型:【 C语言程序设计 】在C语言中,用于打开文件的函数是____,用于关闭文件的函数是____。

Touchdesigner自学笔记之三_touchdesigner怎么让一个模型跟着鼠标移动-程序员宅基地

文章浏览阅读3.4k次,点赞2次,收藏13次。跟随鼠标移动的粒子以grid(SOP)为partical(SOP)的资源模板,调整后连接【Geo组合+point spirit(MAT)】,在连接【feedback组合】适当调整。影响粒子动态的节点【metaball(SOP)+force(SOP)】添加mouse in(CHOP)鼠标位置到metaball的坐标,实现鼠标影响。..._touchdesigner怎么让一个模型跟着鼠标移动

【附源码】基于java的校园停车场管理系统的设计与实现61m0e9计算机毕设SSM_基于java技术的停车场管理系统实现与设计-程序员宅基地

文章浏览阅读178次。项目运行环境配置:Jdk1.8 + Tomcat7.0 + Mysql + HBuilderX(Webstorm也行)+ Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。项目技术:Springboot + mybatis + Maven +mysql5.7或8.0+html+css+js等等组成,B/S模式 + Maven管理等等。环境需要1.运行环境:最好是java jdk 1.8,我们在这个平台上运行的。其他版本理论上也可以。_基于java技术的停车场管理系统实现与设计

Android系统播放器MediaPlayer源码分析_android多媒体播放源码分析 时序图-程序员宅基地

文章浏览阅读3.5k次。前言对于MediaPlayer播放器的源码分析内容相对来说比较多,会从Java-&amp;amp;gt;Jni-&amp;amp;gt;C/C++慢慢分析,后面会慢慢更新。另外,博客只作为自己学习记录的一种方式,对于其他的不过多的评论。MediaPlayerDemopublic class MainActivity extends AppCompatActivity implements SurfaceHolder.Cal..._android多媒体播放源码分析 时序图

java 数据结构与算法 ——快速排序法-程序员宅基地

文章浏览阅读2.4k次,点赞41次,收藏13次。java 数据结构与算法 ——快速排序法_快速排序法