c++ Qt 数据库操作

news2024/11/26 2:41:29

1、准备工作

Qt本身并没有数据库功能,但是Qt支持调用其他主流的数据库产品,并且这些数据库产品统一了Qt的接口,实际上是一种数据库的中间件。

Qt支持以下数据库类型:

嵌入式常用的数据库是sqlite3,本体只有几兆大小。非常适合集成到嵌入式产品中,在Qt5版本及以上也集成了SQLite数据库。因此可以直接通过驱动名称连接SQLite。

数据库编程中需要用到以下几个类:

  • QSqlDatabase

数据库相关类,表示一个数据库连接。

  • QSqlQuery

数据库操作类,可以操作SQL语句

  • QSqlError

数据库错误信息类,用户收集数据库底层传递到Qt中的错误信息。

数据库相关类无法直接使用,需要在.pro配置文件中添加sql模块。

2、连接数据库

主要通过QSqlDatabase类进行连接。相关函数:

1)获得一个数据库连接对象

// 获得一个数据库连接对象
// 参数为数据库类型,详见本章第一节表格(区分大小写)
// 返回值为连接对象
#include <QSqlDatabase>
QSqlDatabase QSqlDatabase:: addDatabase(const QString & type)[static]

2)设置数据库名称

// 设置数据库名称
// 参数因不同的数据库表示不同的涵义。对于SQLite,此函数表示数据库文件名。此文件会在项目中构建目录中生成
void QSqlDatabase:: setDatabaseName(const QString & name)

3)打开数据库连接

// 打开数据库连接
// 返回值为连接打开的结果,如果打开失败,可以通过lastError函数获取错误信息
bool QSqlDatabase:: open()

4)返回上一次的错误信息封装类

错误信息类为QSqlError

// 返回上一次的错误信息封装类
#include <QSqlError>
QSqlError QSqlDatabase:: lastError() const

5)从QSqlError对象中提取错误信息文本

// 从QSqlError对象中提取错误信息文本
#include <QSqlError>
QString QSqlError:: text() const

6)返回数据库连接的打开状态

// 返回数据库连接的打开状态
bool QSqlDatabase:: isOpen() const

7)关闭数据库连接

// 关闭数据库连接
void QSqlDatabase:: close()

dialog.cpp

#include "dialog.h"
#include "ui_dialog.h"
Dialog::Dialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Dialog)
{
    ui->setupUi(this);
    //创建按钮组
    group = new QButtonGroup(this);
    //添加按钮对象
    group->addButton(ui->pushButtonInsert,1);
    group->addButton(ui->pushButtonDelete,2);
    group->addButton(ui->pushButtonUpdate,3);
    group->addButton(ui->pushButtonSelect,4);
    //按钮组连接
connect(group,SIGNAL(buttonClicked(int)),this,SLOT(btnClickedSlots(int)));
    connectD2B();
}
Dialog::~Dialog()
{
    //检查数据库状态
    if(db.isOpen())
    {
        //关闭数据库连接
        db.close();
    }
    delete ui;
}
//连接数据库
void Dialog::connectD2B()
{
    //获取数据库连接对象
    db = QSqlDatabase::addDatabase("QSQLITE");
    //设置数据库名称
    db.setDatabaseName("book_management.db");
    //打开数据库连接
    bool ret = db.open();
    if(ret == true)
    {
        qDebug()<<"打开成功";
    }
    else
    {
        qDebug()<<"打开失败";
        //返回最近错误信息封装类
        QSqlError errorInfo = db.lastError();
        //从错误信息类提取错误信息
        QString text = errorInfo.text();
        //弹窗显示错误信息
        QMessageBox::critical(this,"错误",text);
    }
}
void Dialog::btnClickedSlots(int id)
{
    if(id == 1)
    {
        qDebug()<<"增加";
    }
    else if(id == 2)
    {
        qDebug()<<"删除";
    }
    else if(id == 3)
    {
        qDebug()<<"修改";
    }
    else if(id == 4)
    {
        qDebug()<<"查询";
    }
    else
    {
        qDebug()<<"错误";
    }
}

3、创建表

建表语句(SQL语句):

//表名   id设置为主键 名字文本 价格实数 作者文本
CREATE TABLE book(id INTEGER PRIMARY KEY,name TEXT,price REAL,author TEXT);

CREATE TABLE book(
    id INTEGER PRIMARY KEY,
    name TEXT,
    price REAL,
    author TEXT
);

查看建表是否成功

// 执行SQL语句
// 参数为SQL语句内容
// 返回值为执行的结果,只关心是否成功,其他不管
bool QSqlQuery:: exec(const QString & query)

错误信息

// 与本章第2节的同名函数用法完全一样
QSqlError QSqlQuery::lastError() const

一个操作SQLite的可视化软件

++下载链接:百度网盘 请输入提取码 提取码:hqyj 

//创建表(建表)
void Dialog::creatTable()
{
    //方法1       //表名   id设置为整形主键 名字文本 价格实数 作者文本
     QString sql ="CREATE TABLE book(id INTEGER PRIMARY KEY,name TEXT,price REAL,author TEXT);";
    //方法2
    sql = QString("CREATE TABLE book(\//表名 \
                    id INTEGER PRIMARY KEY,\//id设置为整形主键\
                    name TEXT,\//名字 文本\
                    price REAL,\//价格  实数\
                    author TEXT);\//作者     文本\
                    ");   
    //创建数据库操作
    QSqlQuery sq;
    //执行SQL语句,并检查是否创建表成功
    if(sq.exec(sql))
    {
        qDebug()<<"建表成功";
    }
    else// 建表失败,注意:建表成功或失败都很正常,如果要建的表已经存在,就会建表失败

    {
        //获取错误信息封装类
        QSqlError errorInfo = sq.lastError();
        //从错误信息封装类获取错误信息
        QString text = errorInfo.text();
        qDebug()<<"建表失败"<<text;
    }
}

4、增删改

增删改都需要先录入用户输入,然后把用户输入的数据组装成SQL语句,最后执行。

组装SQL语句有两种方式:

  • 字符串拼接

这种方式实现简单,但是容易拼接错误,且安全性较低。

  • 预处理+占位符

推荐使用这种方式,这种方式需要先编写占位符。预处理SQL语句,交给Qt,Qt内部就知道要执行的SQL语句格式,然后在进行参数和占位符的替换,最终执行。

占位符有两种表示风格:

  • Oracle风格

使用:字段的格式

UPDATE book SET name=:name,price=:price,author=:author WHERE id=:id;

  • ODBC风格

使用?的格式

INSERT INTO book VALUES(?,?,?,?);

预处理SQL语句,此时SQL语句并没有执行,只是送入到了Qt内部。

// 预处理SQL语句,此时SQL语句并没有执行,只是送入到了Qt内部。
// 参数为预处理的SQL语句
// 返回值预处理的结果
bool QSqlQuery:: prepare(const QString & query)

绑定ODBC风格的占位符参数,绑定的时候一定要注意顺序。

// 绑定ODBC风格的占位符参数,绑定的时候一定要注意顺序。
// 参数为要绑定的数据
void QSqlQuery:: addBindValue(const QVariant & val)

增加操作

void Dialog::insertData()
{
    QString name = ui->lineEdit->text();
    if(name == "")
    {
        QMessageBox::warning(this,"提示","请输入书名");
        return;
    }
    QString author = ui->lineEditAuthor->text();
    if(author == "")
    {
        QMessageBox::warning(this,"提示","请输入作者名");
        return;
    }
    int id = ui->spinBox->value();
    double price = ui->doubleSpinBox->value();
    // 预处理的SQL语句
    QString sql = "INSERT INTO book VALUES(?,?,?,?);";
    // 预处理
    QSqlQuery sq;
    sq.prepare(sql);
    // 绑定数据
    sq.addBindValue(id);
    sq.addBindValue(name);
    sq.addBindValue(price);
    sq.addBindValue(author);·
    // 执行绑定好的SQL语句,并检查执行状态
    if(sq.exec())
    {
        QMessageBox::information(this,"通知","数据插入成功");
    }
    else
    {
        // 获取错误信息封装类
        QSqlError info = sq.lastError();
        QString text = info.text();
        QMessageBox::warning(this,"警告","数据插入失败");
    }
}

绑定Oracle风格的占位符参数,绑定可以乱序

// 绑定Oracle风格的占位符参数,绑定可以乱序
// 参数1:占位符
// 参数2:要绑定的数据
void QSqlQuery:: bindValue(const QString & placeholder, const        QVariant & val)

删除操作

// 删除, 按照id删除
void Dialog::deleteData()
{
    int id = ui->spinBox->value();
    // 查询表中id是否存在
    // TODO --

    // 预处理的SQL语句
    QString sql = "DELETE FROM book WHERE id=?";
    QSqlQuery sq;
    sq.prepare(sql); // 预处理

    // 绑定参数
    sq.addBindValue(id);
    // 执行绑定后SQL语句
    if(sq.exec())
    {
        QMessageBox::information(this,"通知","数据删除成功");
    }
    else
    {
        // 获得错误信息封装类
        QSqlError info = sq.lastError();
        QString text = info.text();
        QMessageBox::critical(this,"错误",text);
    }

}

更改操作

//按编号修改数据
void Dialog::updateDate()
{
    //获得用户输入的数据,(全部获得)
    QString name = ui->lineEdit->text();
    if(name == "")
    {
        QMessageBox::warning(this,"提示","请输入书名");
        return;
    }
    QString author = ui->lineEditAuthor->text();
    if(author == "")
    {
        QMessageBox::warning(this,"提示","请输入作者名");
        return;
    }
    int id = ui->spinBox->value();
    double price = ui->doubleSpinBox->value();
    //判断ID在数据库中是否存在

    //预处理语句(oracle风格),不需要注意数据顺序
    QString sql = "UPDATE book SET name=:name,price=:price,author=:author WHERE id=:id";
    //预处理
    QSqlQuery sq;
    sq.prepare(sql);
    //绑定参数
    sq.bindValue(":id",id);
    sq.bindValue(":name",name);
    sq.bindValue(":price",price);
    sq.bindValue(":author",author);
    //执行绑定后的SQL语句
    if(sq.exec())
    {
        QMessageBox::information(this,"提示","数据更改成功");
        return;
    }
    else
    {
        //获取错误信息封装
        QSqlError info = sq.lastError();
        QString text = info.text();
        QMessageBox::critical(this,"错误",text);
    }
}

5、查询

5.1 全查

1)判断查询结果有无数据,如果有数据则移动游标取出,没有返回false

// 判断查询结果有无数据,如果有数据则移动游标取出,没有返回false
bool QSqlQuery:: next()

2)按照字段序号取出对应的值,序号从0开始

// 按照字段序号取出对应的值,序号从0开始
// 返回值QVariant类型,可以根据需要直接转换为所需要类型
QVariant QSqlQuery:: value(int index) const

3)按照字段名称取出对应的值

// 按照字段名称取出对应的值
// 返回值QVariant类型,可以根据需要直接转换为所需要类型
QVariant QSqlQuery:: value(const QString & name) const

void Dialog::selectAll()
{
    //清空textBrowser
    ui->textBrowser->clear();
    QString sql = "SELECT * FROM book";
    QSqlQuery sq;
    if(sq.exec(sql))
    {
        while(sq.next())
        {
            //取出一条记录中的每个字段值
            QString id = sq.value(0).toString();
            QString name = sq.value(1).toString();
            QString price = sq.value("price").toString();
            QString author = sq.value("author").toString();
            //显示
            QString text = id.append("-")+name.append("-")+price.append("-")+author;
            ui->textBrowser->append(text);
        }
    }
}

查看id是否存在

bool Dialog::isDateExists(int id)
{
    QString idText = QString::number(id);
    QString sql = "SELECT * FROM book WHERE id=";
    sql.append(idText);
    QSqlQuery sq;
    if(sq.exec(sql))
    {
        return sq.next();
    }
    else
    {
        return false;
    }
}

5.2模糊查询

可以使用LIKE关键字配合两个通配符实现模糊查询。

通配符

  • %

任意多个(0、1、2、3........n)字符

  • _

任意一个字符

【例子】查找‘瑞’ 字辈的信息

SELECT * FROM book WHERE name LIKE "_瑞%"

【例子】查找姓名中包含“瑞”这个字的人员信息。

SELECT * FROM book WHERE name LIKE "%瑞%"

dialog.cpp

//模糊查询
void Dialog::selectLike()
{
    //获取要查询的内容
    QString name = ui->lineEdit->text();
    if(name == "")
    {
        QMessageBox::warning(this,"提示","请输入书名");
        return;
    }
    else
    {
        //预处理
        QString sql = "SELECT * FROM book WHERE name LIKE ?";
        QSqlQuery sq;
        sq.prepare(sql);
        //SQL语句处理,%name%
        sq.addBindValue(name.prepend("%").append("%"));
        if(sq.exec())
        {
            //添加状态位置,检查是否查询到结果
            bool reState = true;
            //清空上次查询内容
            ui->textBrowser->clear();
            while(sq.next())
            {
                //数据库数据遍历
                QString id = sq.value(0).toString();
                QString name = sq.value(1).toString();
                QString price = sq.value(2).toString();
                QString author = sq.value(3).toString();
                //显示
                QString text = id.append("-")+name.append("-")+price.append("-")+author;
                ui->textBrowser->append(text);
                reState =false;
            }
            //查询结果判断
            if(reState)
            {
                QMessageBox::information(this,"提示","没有相关结果");
                return;
            }
        }
        else
        {
            //错误信息弹窗
            QSqlError err = sq.lastError();
            QString text = err.text();
            QMessageBox::critical(this,"错误",text);
        }
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1451349.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

win7自带截图工具保存失效解决办法

今日发现一台远航技术的win7中自带的截图工具使用时正常&#xff0c;保存图片时没有弹出保存位置的对话窗口&#xff0c;无法正常保存图片。解决方案如下&#xff1a; 1、进入注册表编辑器。开始-搜索程序和文件-输入 regedit 按下回车键&#xff0c;打开注册表&#xff1b; 2、…

auto关键字详讲

目录 1.问题思考 2.auto关键字介绍 3. 早期auto的缺陷&#xff1a; 4.什么叫自动存储器&#xff1f; 5. c标准auto关键字 5.1auto的使用细节 5.2 auto什么时候不能推导变量的类型呢&#xff1f; 5.3基于范围的for循环 5.3.1范围for的用法 5.3.2 范围for的使用条件 6.…

家庭动态网络怎么在公网访问主机数据?--DDNS配置(动态域名解析配置)

前言 Dynamic DNS是一个DNS服务。当您的设备IP地址被互联网服务提供商动态变更时,它提供选项来自动变更一个或多个DNS记录的IP地址。 此服务在技术术语上也被称作DDNS或是Dyn DNS 如果您没有一个静态IP,那么每次您重新连接到互联网是IP都会改变。为了避免每次IP变化时手动更…

14. 推荐系统之矩阵分解

本文为 「茶桁的 AI 秘籍 - BI 篇 第 14 篇」 文章目录 矩阵分解 ALS常用推荐算法什么是矩阵分解矩阵分解的目标函数 Hi&#xff0c;你好。我是茶桁。 新年过后&#xff0c;咱们要开始学一些新内容了。从今天开始&#xff0c;要给大家去讲解的是关于推荐系统的内容。推荐系统的…

「递归算法」:两两交换链表中的节点

一、题目 给你一个链表&#xff0c;两两交换其中相邻的节点&#xff0c;并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题&#xff08;即&#xff0c;只能进行节点交换&#xff09;。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4] 输出&#xf…

【sgCreatePinyin】自定义小工具:敏捷开发→自动化生成拼音字段名称(字段名生成工具)

源码 <template><!-- 前往https://blog.csdn.net/qq_37860634/article/details/136126311 查看使用说明 --><div :class"$options.name"><div class"sg-head">拼音字段生成工具</div><div class"sg-container&qu…

C#,计算几何,贝塞耳插值(Bessel‘s interpolation)的算法与源代码

Friedrich Wilhelm Bessel 1 贝塞耳插值&#xff08;Bessels interpolation&#xff09; 首先要区别于另外一个读音接近的插值算法&#xff1a;贝塞尔插值&#xff08;Bzier&#xff09;。 &#xff08;1&#xff09;读音接近&#xff0c;但不是一个人&#xff1b; &#x…

《剑指 Offer》专项突破版 - 面试题 47 : 二叉树剪枝(C++ 实现)

题目链接&#xff1a;LCR 047. 二叉树剪枝 - 力扣&#xff08;LeetCode&#xff09; 题目&#xff1a; 一棵二叉树的所有节点的值要么是 0 要么是 1&#xff0c;请剪除该二叉树中所有节点的值全都是 0 的子树。例如&#xff0c;在剪除下图 (a) 中二叉树中所有节点值都为 0 的…

OpenAI又出王炸,Sora是否要开启视频AI新时代?

OpenAI又出王炸&#xff0c;Sora是否要开启视频AI新时代&#xff1f; 关注微信公众号 DeepGoAI 前几天我们还在讨论 如何让ChatGPT3.5变得更聪明 今天OpenAI就带着新王炸出现了 如同ChatGPT一般 在计算机领域掀起轩然大波 开启真正视频AI新时代 那就是 Sora 很多同学可…

MinIO 和 Apache Tika:文本提取模式

Tl;dr: 在这篇文章中&#xff0c;我们将使用 MinIO Bucket Notifications 和 Apache Tika 进行文档文本提取&#xff0c;这是大型语言模型训练和检索增强生成 LLM和RAG 等关键下游任务的核心。 前提 假设我想构建一个文本数据集&#xff0c;然后我可以用它来微调 LLM.为了做…

【实战】二、Jest难点进阶(一) —— 前端要学的测试课 从Jest入门到TDD BDD双实战(五)

文章目录 一、Jest 前端自动化测试框架基础入门二、Jest难点进阶1.snapshot 快照测试 学习内容来源&#xff1a;Jest入门到TDD/BDD双实战_前端要学的测试课 相对原教程&#xff0c;我在学习开始时&#xff08;2023.08&#xff09;采用的是当前最新版本&#xff1a; 项版本babe…

STM32F1 - 中断系统

Interrupt 1> 硬件框图2> NVIC 中断管理3> EXTI 中断管理3.1> EXTI与NVIC3.2> EXTI内部框图 4> 外部中断实验4.1> 实验概述4.2> 程序设计 5> 总结 1> 硬件框图 NVIC&#xff1a;Nested Vectored Interrupt Controller【嵌套向量中断控制器】 管理…

分布式锁redisson

文章目录 1. 分布式锁1.1 基本原理和实现方式对比synchronized锁在集群模式下的问题多jvm使用同一个锁监视器分布式锁概念分布式锁须满足的条件分布式锁的实现 1.2 基于Redis的分布式锁获取锁&释放锁操作示例 基于Redis实现分布式锁初级版本ILock接口SimpleRedisLock使用示…

OS设备管理

设备管理 操作系统作为系统资源的管理者&#xff0c;其提供的功能有&#xff1a;处理机管理、存储器管理、文件管理、设备管理。其中前三个管理都是在计算机的主机内部管理其相对应的硬件。 I/O设备 I/O即输入/输出。I/O设备即可以将数据输入到计算机&#xff0c;或者可以接收…

差分与前缀和的含义、应用及示例代码

差分与前缀和 求差分 与 求前缀和 是一组“互逆”的操作。 使用差分 可以实现&#xff1a;以时间复杂度为O(1)&#xff0c;对数组区间各元素 / 矩阵区域各元素 一个常数。 使用前缀和 可以实现&#xff1a;以时间复杂度为O(1)&#xff0c;对数组区间各元素 / 矩阵区域各元素…

C++ 图上 bfs(五十八)【第五篇】

今天我们来学习一下图上bfs。 1.图上bfs 在图上&#xff0c;我们也可以进行 BFS&#xff0c;也可以解决图上 DFS 能解决的问题&#xff0c;比如连通块。 除此以外&#xff0c;根据 BFS 的性质&#xff0c;第一次到一个点的时候记下来的步数一定是到从起点到这个点的最小步数&…

Netty Review - 直接内存的应用及源码分析

文章目录 Pre概述应用访问效率&#xff1a; 堆内存 VS 直接内存申请效率&#xff1a; 堆内存 VS 直接内存数据存储结构&#xff1a; 堆内存 VS 直接内存结论 ByteBuffer.allocateDirect 源码分析unsafe.allocateMemory(size) ---> C方法 JVM参数 -XX:MaxDirectMemorySize直接…

并发编程(1)基础篇

1 概览 1.1 这门课讲什么 这门课中的【并发】一词涵盖了在 Java 平台上的 进程线程并发并行 以及 Java 并发工具、并发问题以及解决方案&#xff0c;同时也会讲解一些其它领域的并发 1.2 为什么学这么课 我工作中用不到并发啊&#xff1f; 那你还是没有接触到复杂项目. …

【Python--网络编程之Ping命令的实现】

&#x1f680; 作者 &#xff1a;“码上有前” &#x1f680; 文章简介 &#xff1a;Python开发技术 &#x1f680; 欢迎小伙伴们 点赞&#x1f44d;、收藏⭐、留言&#x1f4ac; Python网络编程之Ping命令的实现 往期内容代码见资源&#xff0c;效果图如下一、实验要求二、协…

【AIGC】Stable Diffusion 的提示词入门

一、正向提示词和反向提示词 Stable Diffusion 中的提示词通常用于指导用户对生成的图像进行控制。这些提示词可以分为正向提示词&#xff08;Positive Prompts&#xff09;和反向提示词&#xff08;Negative Prompts&#xff09;两类&#xff0c;它们分别影响图像生成过程中的…