Qt之数据库使用(十四)

打印 上一主题 下一主题

主题 876|帖子 876|积分 2628

Qt开发 系列文章 - QSqlDatabase-SQLite(十四)

目录
媒介
一、SQLite
二、SQLite使用
1.添加SQL
2.创建数据库
3.定义类及相关变量
4.相关功能函数
5.用户类定义
6.用户类使用
7.效果演示
8.SQLite数据库
总结

媒介

‌Qt支持的数据库包罗SQLite、MySQL、PostgreSQL、ODBC等‌。其中,SQLite是Qt默认支持的数据库,无需额外的驱动就可以使用,适当轻量级的应用,不需要多用户、大数据量的场景。对于大型应用,MySQL和PostgreSQL则是更好的选择,它们提供了更强盛的数据处理能力‌。本文将讲授SQLite的设计使用。

一、SQLite

SQLite是一款轻量级的嵌入式数据库,它的数据库就是一个文件,可以直接通过Qt的SQL模块操纵。SQLite的上风在于无需配置、轻量级,适当不需要多用户、大数据量的场景‌。在Qt中使用SQLite时,可以通过QSqlDatabase类来创建一个数据库连接,使用addDatabase()函数指定命据库类型为"QSQLITE",然后设置数据库名字并打开数据库‌ 。
二、SQLite使用

Qt中对SQLite的使用,通常需要用到以下几个相关类:

  • QSqlDatabase类:数据库连接类,表现一个数据库连接;
  • QSqlQuery类:数据库操纵类,可以操纵SQL语句;
  • QSqlError类:数据库错误信息类,用户网络数据库底层通报到Qt中的错误信息。
下面将讲授SQLite在Qt中的使用。
1.添加SQL

想使用SQL,首先需要先在.pro项目配置文件中添加sql模块,如下所示。
  1. QT       += sql
复制代码
2.创建数据库

在原有的Qt项目上新建一个类,用于专门操纵数据库的,并将该类属于工程项目主窗口的私有变量(固然你也可以不创建该类,直接在项目在构造函数上定义该数据库,进行使用)。
在Qt原有项目怎样新建一个类,在博主以前的博文有详细的先容,这里本文不做先容,将设计在新建的类的构造函数处定义数据变量,具体有以下步调。

  • 先打印出,电脑所装Qt支持的数据库种类;
  • 创建数据库文件的路径及名称;
  • 添加SQLite驱动,创建连接;
  • 看SQLite是否存在,若不存在,主动创建;若存在,在已有的数据库上进行;
  • 打开创建的数据库;
  • 开启事务,预备进行操纵;
  • 创建数据库操纵类QSqlQuery;
  • 在数据库上创建多少表格;
  • 提交事务到数据库,并生存更改。
具体实现,代码如下(示例):
  1. void testhread::InitQSqlite()
  2. {
  3.     //**0**打印Qt支持的数据库
  4.     qDebug() << "QSqlDatabase=" << QSqlDatabase::drivers();
  5.     //**1**创建数据库名称及路径
  6.     QTime systime = QTime::currentTime();
  7.     QString saveFileFolder = QApplication::applicationDirPath()+"/savefile/";
  8.     QDir folder; //创建文件夹
  9.     if(!folder.exists(saveFileFolder))
  10.         folder.mkpath(saveFileFolder); //不存在则创建文件夹
  11.     QString DBFileName = "dbmsg" + systime.toString("hh-mm-ss") + ".db";
  12.     QString DBFilePath = saveFileFolder + DBFileName;
  13.     //**2**添加SQLite驱动 创建连接
  14.     m_db = QSqlDatabase::addDatabase("QSQLITE");
  15.     //**3**SQLite不存在,自动创建;已经存在,在已有的数据库上进行。
  16.     m_db.setDatabaseName(DBFilePath);
  17.     //**4**打开数据库
  18.     if(!m_db.open()){
  19.         qDebug() << "Failed to open database!" << m_db.lastError().text();
  20.         return;
  21.     } else
  22.         qInfo() << "Successfully opened database! SQLite Type.";
  23.     //**5**开始事务
  24.     if (!m_db.transaction()) {
  25.         qDebug() << "Failed to begin transaction";
  26.         return;
  27.     }
  28.     //**6**创建数据库QSqlQuery
  29.     sql = new QSqlQuery(m_db);
  30.     //**7**在数据库上创建表格-student
  31.     QString createSql = QString("CREATE TABLE IF NOT EXISTS student (\
  32.                               id INT PRIMARY KEY NOT NULL,name TEXT NOT NULL,\
  33.                               age INT NOT NULL,height INT NOT NULL)");
  34.     if(!sql->exec(createSql))
  35.         qDebug() << "Error: Fail to create student table. " << sql->lastError();
  36.     else
  37.         qDebug() << "student table create successful!";
  38.     //在数据库上创建表格-状态反馈
  39.     createSql = QString("CREATE TABLE IF NOT EXISTS MachineStatus(\
  40.                                Systime INTEGER (4) PRIMARY KEY,stat INTEGER (1),MainVer INTEGER (1),SubVer INTEGER (1),\
  41.                                Type INTEGER (1),Broad INTEGER (1),Online INTEGER (1))");
  42.     if(!sql->exec(createSql))
  43.         qDebug() << QString("Fail to create MachineStatus table.")<< sql->lastError();
  44.     else
  45.         qDebug() << "MachineStatus table create successful!";
  46.     //**8**提交事务并保存更改
  47.     if (!m_db.commit()) {
  48.         qDebug() << "Failed to commit transaction";
  49.         return;
  50.     }
  51. }
复制代码
3.定义类及相关变量

上一步我们在原有的Qt项目上新建一个类,用于专门操纵数据库的,这里来定义该类。具体实现,代码如下(示例):
  1. #ifndef TESTHREAD_H
  2. #define TESTHREAD_H
  3. #include <QThread>
  4. #include <QDebug>
  5. #include <QByteArray>
  6. #include <QTableView>
  7. #include <QSqlQueryModel>
  8. #include <QSqlDatabase>
  9. #include <QSqlError>
  10. #include <QFile>
  11. #include <QSqlQuery>
  12. #include <QSqlRecord>
  13. #include <QTime>
  14. #include <QDir>
  15. #include "qstandarditemmodel.h"
  16. #define MAXROWCNT 20
  17. #define MAXROWHIG 4
  18. #define MAXCOLWID 79
  19. //状态反馈信息
  20. typedef struct
  21. {
  22.         qint32 Systime;
  23.         quint8 stat, MainVer, SubVer, Type, Broad;
  24.         quint8 Online;
  25. }FK_SatFBInfo_struct;
  26. class testhread : public QThread
  27. {
  28.     Q_OBJECT
  29. public:
  30.     testhread();
  31.     ~testhread(){}
  32.     QTableView *UNKNTableView;
  33.     FK_SatFBInfo_struct *FKSatFBInfo;
  34.     QSqlDatabase m_db;           //数据库对象
  35.     QSqlQuery *sql;
  36.     bool g_flag;
  37.     bool pushmsg_flag;
  38.     void InitTableView(void);
  39. protected:
  40.     void InitQSqlite(void);
  41.     void run(void);
  42.     void ShowFKSFInfo(FK_SatFBInfo_struct *pFKSF);
  43. private:
  44.     QStandardItemModel* m_Model;
  45. };
  46. #endif // TESTHREAD_H
复制代码
4.相关功能函数

相关功能函数主要包罗构造函数(实现变量及数据库初始化)、线程run()函数。
这里讲授下,接纳线程实现的方式,初始化(定义好)数据库文件后,然后通过UI界面上来控制线程启动,和决定是否向数据库不间断地插入数据,完成数据生存到数据库文件上,末了还通过UI界面表格将数据库的数据刷到表格上。至于为啥如许设计实现,效率更高更快,一般在网络、工业上数据处理均接纳如许的方式。
具体实现,代码如下(示例):
  1. #include "testhread.h"
  2. testhread::testhread()
  3. {
  4.     qRegisterMetaType<QVector<int>>("QVector<int");
  5.     qRegisterMetaTypeStreamOperators<QVector<int>>();
  6.     g_flag = false;
  7.     pushmsg_flag = false;
  8.     memset(&FKSatFBInfo,0,sizeof(FKSatFBInfo));
  9.     InitQSqlite();
  10. }
  11. void testhread::InitTableView(void)
  12. {
  13.     m_Model = new QStandardItemModel;
  14.     QStringList list;
  15.     list << QString("Time")<<"运行状态"<<"主版本号"<<"子版本号"<<"项目类型"<<"板上自检"<<"在线状态";
  16.     // 设置表格行数和列数
  17.     m_Model = new QStandardItemModel(MAXROWCNT, list.size(), this);
  18.     // 设置表头
  19.     m_Model->setHorizontalHeaderLabels(list);
  20.     UNKNTableView->setModel(m_Model);
  21.     //UNKNTableView->setAutoScroll(true);
  22.     UNKNTableView->setEditTriggers(QAbstractItemView::NoEditTriggers);
  23.     for(quint8 i= 0; i<list.size(); i++)
  24.         UNKNTableView->setColumnWidth(i, MAXCOLWID);
  25.     for(quint16 i= 0; i<MAXROWCNT; i++)
  26.         UNKNTableView->setRowHeight(i, MAXROWHIG);
  27. }
  28. void testhread::run()
  29. {
  30.     FK_SatFBInfo_struct FKSatFBInfo;
  31.     while(g_flag)
  32.     {
  33.         if (pushmsg_flag) {
  34.             //插入表格
  35.             QString tempinfo = QString("INSERT INTO MachineStatus(Systime,stat,MainVer,"
  36.                                        "SubVer,Type,Broad,Online) VALUES(?,?,?,?,?,?,?)");
  37.             sql->prepare(tempinfo);
  38.             FKSatFBInfo.Systime += 500;
  39.             FKSatFBInfo.stat = 3;
  40.             FKSatFBInfo.MainVer = 1;
  41.             FKSatFBInfo.SubVer = 2;
  42.             FKSatFBInfo.Type = 0;
  43.             FKSatFBInfo.Broad = 0;
  44.             FKSatFBInfo.Online = 1;
  45.             sql->addBindValue(FKSatFBInfo.Systime);
  46.             sql->addBindValue(FKSatFBInfo.stat);
  47.             sql->addBindValue(FKSatFBInfo.MainVer);
  48.             sql->addBindValue(FKSatFBInfo.SubVer);
  49.             sql->addBindValue(FKSatFBInfo.Type);
  50.             sql->addBindValue(FKSatFBInfo.Broad);
  51.             sql->addBindValue(FKSatFBInfo.Online);
  52.             if(!sql->exec())
  53.                 qDebug() << "Fail to insert data. " << sql->lastError().text();
  54.             ShowFKSFInfo(&FKSatFBInfo);
  55.         }
  56.         msleep(500);
  57.     }
  58. }
  59. void testhread::ShowFKSFInfo(FK_SatFBInfo_struct *pFKSF)
  60. {
  61.     static quint16 cnt=0;
  62.     if(cnt == (MAXROWCNT)){
  63.         for(quint16 i=0;i<MAXROWCNT;i++){
  64.             for(quint8 j=0;j<7;j++){
  65.                 auto tempIndex = UNKNTableView->model()->index(i, j);
  66.                 m_Model->clearItemData(tempIndex);
  67.             }
  68.         }
  69.         cnt = 0;
  70.     }
  71.     m_Model->setData(m_Model->index(cnt, 0), pFKSF->Systime);
  72.     m_Model->setData(m_Model->index(cnt, 1), "空闲态0");
  73.     m_Model->setData(m_Model->index(cnt, 2), pFKSF->MainVer);
  74.     m_Model->setData(m_Model->index(cnt, 3), pFKSF->SubVer);
  75.     m_Model->setData(m_Model->index(cnt, 4), pFKSF->Type);
  76.     m_Model->setData(m_Model->index(cnt, 5), pFKSF->Broad);
  77.     m_Model->setData(m_Model->index(cnt, 6), pFKSF->Online);
  78.     auto lastModelIndex = UNKNTableView->model()->index(cnt, 0);
  79.     UNKNTableView->scrollTo(lastModelIndex); // 滚动到当前行
  80.     cnt++;
  81. }
复制代码
5.用户类定义

用户类主要是指项目主窗口变量,定义了其构造函数、析构函数、UI界面信号槽函数、及相关类定义为私有变量,具体实当代码如下(示例):
  1. #ifndef CSQLTEST_H
  2. #define CSQLTEST_H
  3. #include <QMainWindow>
  4. #include "testhread.h"
  5. namespace Ui {
  6. class CSqlTest;
  7. }
  8. class CSqlTest : public QMainWindow
  9. {
  10.     Q_OBJECT
  11. public:
  12.     explicit CSqlTest(QWidget *parent = nullptr);
  13.     ~CSqlTest();
  14. private slots:
  15.     void on_pBinsert_clicked();
  16.     void on_pBchange_clicked();
  17.     void on_pBlookup_clicked();
  18.     void on_pBexit_clicked();
  19.     void on_pBclea_clicked();
  20.     void on_pBConditional_clicked();
  21.     void on_pushButton_6_clicked();
  22.     void on_pBstarthd_clicked();
  23.     void on_pBpushmsg_clicked();
  24. private:
  25.     Ui::CSqlTest *ui;
  26.     QSqlQueryModel  *m_pModel; //数据模型对象
  27.     testhread*      DBthd;
  28.     void displayRecord(QSqlQuery query); //展示query所查询到的数据
  29. };
  30. #endif // CSQLTEST_H
复制代码
6.用户类使用

完成相关类私有变量初始化,主要包罗Ui::CSqlTest *ui、QSqlQueryModel  *m_pModel、testhread *DBthd。还实现了UI界面上的信号槽功能,主要包罗想表格中插入数据、更改表格、查询所有表格上所有数据、清除表等等,具体看UI界面,实当代码如下(示例):
  1. #include "csqltest.h"
  2. #include "ui_csqltest.h"
  3. CSqlTest::CSqlTest(QWidget *parent)
  4.     : QMainWindow(parent)
  5.     , ui(new Ui::CSqlTest)
  6. {
  7.     ui->setupUi(this);
  8.     /****创建线程类变量*****/
  9.     DBthd = new testhread();
  10.     /****将UI上表格视图地址赋值到线程变量上*****/
  11.     DBthd->UNKNTableView = ui->UNTableView;
  12.     /****表格初始化*****/
  13.     DBthd->InitTableView();
  14. }
  15. CSqlTest::~CSqlTest()
  16. {
  17.     if(DBthd->isRunning()) {
  18.         DBthd->terminate();
  19.         DBthd->wait(1);
  20.     }
  21.     if(DBthd != nullptr)
  22.         delete DBthd;
  23.     delete ui;
  24. }
  25. void CSqlTest::on_pBstarthd_clicked()
  26. {
  27.     if(ui->pBstarthd->text() == "启动线程") {
  28.         DBthd->g_flag = true;
  29.         DBthd->start();
  30.         ui->pBstarthd->setText("停止线程");
  31.     }
  32.     else {
  33.         DBthd->g_flag = 0;
  34.         ui->pBstarthd->setText("启动线程");
  35.     }
  36. }
  37. //显示在表上QSqlQueryModel
  38. void CSqlTest::on_pushButton_6_clicked()
  39. {
  40.     //为数据模型设置父对象
  41.     m_pModel = new QSqlQueryModel(DBthd);
  42.     //查询数据
  43.     m_pModel->setQuery(QString("select * from student"));
  44.     if(m_pModel->lastError().isValid()) {
  45.         qDebug() << "Data query failed!!" << m_pModel->lastError().text();
  46.         return;
  47.     }
  48.     //设置数据模型指定列的列标题(若是不设置,则标题为和数据表上一样)
  49.     m_pModel->setHeaderData(0, Qt::Horizontal, "学号");
  50.     m_pModel->setHeaderData(1, Qt::Horizontal, "姓名");
  51.     m_pModel->setHeaderData(2, Qt::Horizontal, "年龄");
  52.     m_pModel->setHeaderData(3, Qt::Horizontal, "身高");
  53.     //将数据模型设置到tableView控件上
  54.     ui->tableView->setModel(m_pModel);
  55. }
  56. void CSqlTest::on_pBinsert_clicked()
  57. {
  58.     //插入表格
  59.     QSqlQuery p;
  60.     int id = ui->lineEdit_3->text().toInt();
  61.     QString name = ui->lineEdit_2->text();
  62.     int age = ui->lineEdit->text().toInt();
  63.     int height = ui->lineEdit_4->text().toInt();
  64.     QString tempinfo = QString("INSERT INTO student(id, name, age, height) VALUES(?,?,?,?)");
  65.     p.prepare(tempinfo);
  66.     p.addBindValue(id);
  67.     p.addBindValue(name);
  68.     p.addBindValue(age);
  69.     p.addBindValue(height);
  70.     if(!p.exec())
  71.         qDebug() << "Fail to insert data. " << p.lastError().text();
  72. }
  73. void CSqlTest::displayRecord(QSqlQuery query)
  74. {
  75.     //获取一个记录对象
  76.     QSqlRecord rec =  query.record();
  77.     QString columTitle(""); //用于组列标题的变量
  78.     for(int index = 0; index != rec.count(); ++index) {
  79.         //循环获取每个列标题,并添加到列标题字符串中
  80.         columTitle.append(rec.fieldName(index) + "\t");
  81.     }
  82.     //将列标题添加到显示控件中
  83.     ui->textBrowser->append(columTitle);
  84.     //循环获取每条记录
  85.     while (query.next())
  86.     {
  87.         //将当前记录的数据组成字符串,然后添加到显示控件中
  88.         QString record("");
  89.         for(int index = 0; index != rec.count(); ++index) {
  90.             record.append(query.value(index).toString() + "\t");
  91.         }
  92.         ui->textBrowser->append(record);
  93.     }
  94.     ui->textBrowser->append("================Run successfully==================\n");
  95. }
  96. void CSqlTest::on_pBlookup_clicked()
  97. {
  98.     QString tempinfo = "SELECT name FROM sqlite_master WHERE type='table';";
  99.     if (!DBthd->sql->exec(tempinfo)) {
  100.         qDebug() << "Error: Unable to execute query:" << DBthd->sql->lastError().text();
  101.     }
  102.     else{
  103.         QStringList tableNames;
  104.         while (DBthd->sql->next()) {
  105.             QString name = DBthd->sql->value(0).toString();
  106.             tableNames.append(name);
  107.         }
  108.         // 查询所有表上所有数据
  109.         for (const QString &name : tableNames) {
  110.             ui->textBrowser->append(QString("查询%1表所有数据:").arg(name));
  111.             tempinfo = QString("SELECT * FROM %1").arg(name); // 从"student"这个表中查询出所有的数据, *表示查询表中的所有列
  112.             if(!DBthd->sql->exec(tempinfo))
  113.                 qDebug() << "Error: Fail to query table. " << DBthd->sql->lastError();
  114.             else
  115.                 displayRecord(*(DBthd->sql));
  116.         }
  117.     }
  118.     //查询完成后结束查询 清理和释放资源
  119.     //DBthd->sql->finish();
  120. }
  121. void CSqlTest::on_pBConditional_clicked()
  122. {
  123.     QSqlQuery p;
  124.     //添加准备执行的SQL语句(条件查询)
  125.     p.prepare("select * from student where age > :age and id like ? ");
  126.     p.bindValue(":age", 23);    //指定标识符赋值
  127.     p.bindValue(1, "003");      //根据标识符下标赋值(从0开始)
  128.     p.exec();   //直接使用空的exec运行
  129.     ui->textBrowser->append("条件查询:");
  130.     displayRecord(p);
  131.     p.finish();
  132.     //更新操作
  133.     bool flag = p.exec("update student set age = 30 where id like '003'");
  134.     if(!flag)
  135.         return;
  136.     ui->textBrowser->append("更新成功!!!!!!!!!!");
  137. }
  138. void CSqlTest::on_pBexit_clicked()
  139. {
  140.     DBthd->m_db.close();
  141.     close();
  142. }
  143. void CSqlTest::on_pBclea_clicked()
  144. {
  145.     // 获取数据库中的所有表格名称
  146.     QStringList tables = DBthd->m_db.tables();
  147.     foreach (const QString& table, tables) {
  148.         qDebug() << table;
  149.     }
  150.     if(tables.size() <= 1){
  151.         return;
  152.     }
  153.     //删除数据表
  154.     QSqlQuery p;
  155.     for(int i=0;i<(tables.size()-1);i++){
  156.         p.exec(QString("DROP TABLE %1").arg(tables.at(i)));
  157.     }
  158.     if(p.exec())
  159.         qDebug() << p.lastError();
  160.     else
  161.         qDebug() << "deleted table success";
  162. }
  163. void CSqlTest::on_pBchange_clicked()
  164. {
  165.     //在表格上更改student信息
  166.     QString tempinfo = QString("UPDATE student SET name=:name,age=:age,height=:height WHERE id=:id");
  167.     int id = ui->lineEdit_3->text().toInt();
  168.     QString name = ui->lineEdit_2->text();
  169.     int age = ui->lineEdit->text().toInt();
  170.     int height = ui->lineEdit_4->text().toInt();
  171.     DBthd->sql->prepare(tempinfo);
  172.     DBthd->sql->bindValue(":id",id);
  173.     DBthd->sql->bindValue(":name",name);
  174.     DBthd->sql->bindValue(":age",age);
  175.     DBthd->sql->bindValue(":height",height);
  176.     if(!DBthd->sql->exec())
  177.         qDebug() << DBthd->sql->lastError();
  178.     else
  179.         qDebug() << "updated data success!";
  180. }
  181. void CSqlTest::on_pBpushmsg_clicked()
  182. {
  183.     if(ui->pBpushmsg->text() == "压力测试") {
  184.         DBthd->pushmsg_flag = true;
  185.         ui->pBpushmsg->setText("停止测试");
  186.     }
  187.     else {
  188.         DBthd->pushmsg_flag = 0;
  189.         ui->pBpushmsg->setText("压力测试");
  190.     }
  191. }
复制代码
7.效果演示

完成上面代码后,编译运行,效果如下。

8.SQLite数据库

软件运行完后,在生存的目录路径下面,找到数据库文件,如下。其中dbmsg16-32-19.db文件在运行时按过按钮“清除旧表”,导致内里的内容被清空。

重新运行后,打开dbmsg16-36-58.db文件内容如下,可以看到生存的数据内容。

注意事项:要打开.db文件,需下载安装SQLiteStudio,博主使用的是SQLiteStudio-3.2.1版本的,相关链接见文末,内里已经下载好了的,直接安装使用即可。

总结

博文中相应的工程代码Qt-Case.zip 利用Qt开发软件进行编的例程,为博文提供案例-CSDN文库。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

正序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

万有斥力

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表