Qt中操作SQLite数据库

Qt中操作SQLite数据库0.前言SQLite是一款开源、轻量级、跨平台的数据库,无需server,无需安装和管理配置。它的设计目标是嵌入式的,所以很适合小型应用,也是Qt应用开发种常用的一种数据库。1.驱动QtSQL模块使用驱动程序插件(plugins)与不同的数据库API进行通信。由于Qt的SQL模块API与数据库无关,因此所有特定于数据库的代码都包含在这些驱动程序中。Qt提供了几个驱动程序,也可以添加其他驱动程序。提供驱动程序源代码,可用作编写自己的驱动程序的模型。QtCreator在*.pro中引入sq

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全家桶1年46,售后保障稳定

0.前言

SQLite是一款开源、轻量级、跨平台的数据库,无需server,无需安装和管理配置。它的设计目标是嵌入式的,所以很适合小型应用,也是Qt应用开发种常用的一种数据库。

1.驱动

Qt SQL模块使用驱动程序插件(plugins)与不同的数据库API进行通信。由于Qt的SQL模块API与数据库无关,因此所有特定于数据库的代码都包含在这些驱动程序中。Qt提供了几个驱动程序,也可以添加其他驱动程序。提供驱动程序源代码,可用作编写自己的驱动程序的模型。

QtCreator在*.pro中引入sql模块(QT+=sql),或是VS中在Qt VS Tool里勾选上sql模块,就可以使用该模块的接口了。

可以使用QSqlDatabase::drivers()获取驱动程序列表并打印,Qt5.9.7输出如下:

Qt中操作SQLite数据库

其中,SQLite是一个进程内数据库,这意味着没有必要拥有数据库服务器。SQLite在单个文件上运行,在打开连接时必须将其设置为数据库名称。如果该文件不存在,SQLite将尝试创建它。。

2.初相遇

/*
 * ... ...
 * 我喜欢那样的梦
 * 在梦里 一切都可以重新开始
 * 一切都可以慢慢解释
 * 心里甚至还能感觉到所有被浪费的时光
 * 竟然都能重回时的狂喜和感激
 * ... ...
 * 
 *                ----席慕容《初相遇》
 */


#include <QSqlDatabase>
#include <QDebug>

void initDb()
{   
    //qDebug()<<QSqlDatabase::drivers();//打印驱动列表
    QSqlDatabase db;
    //检测已连接的方式 - 默认连接名
    //QSqlDatabase::contains(QSqlDatabase::defaultConnection)
    if(QSqlDatabase::contains("qt_sql_default_connection"))
        db = QSqlDatabase::database("qt_sql_default_connection");
    else
        db = QSqlDatabase::addDatabase("QSQLITE");
    //检测已连接的方式 - 自定义连接名
    /*if(QSqlDatabase::contains("mysql_connection"))
        db = QSqlDatabase::database("mysql_connection");
    else
        db = QSqlDatabase::addDatabase("QSQLITE","mysql_connection");*/
    //设置数据库路径,不存在则创建
    db.setDatabaseName("sqltest.db");
    //db.setUserName("gongjianbo");  //SQLite不需要用户名和密码
    //db.setPassword("qq654344883");
    
    //打开数据库
    if(db.open()){
        qDebug()<<"open success";
        //关闭数据库
        db.close();
    }
    
}

Jetbrains全家桶1年46,售后保障稳定

 上面的代码中,先是创建了一个QSqlDatabase对象,该类用于处理数据库的连接。contains方法用于查看给定的连接名称是否在连接列表中,database方法获取数据库连接,前提是已使用addDatabase添加数据库连接。addDatabase声明如下:

QSqlDatabase QSqlDatabase::addDatabase(const QString &type, const QString &connectionName = QLatin1String(defaultConnection)) [static]

第一个参数对应驱动名,第二个参数为连接名称 ,如果不使用默认连接名称“qt_sql_default_connection”的话需要填写该参数。

设置了驱动及连接名称后,就是设置数据库文件的名称/路径,因为SQLite不需要用户名和密码,接下来直接就可以通过open和close函数来打开关闭该数据库了。

此外,如果需要在内存中创建数据库,而不是指定一个文件,可以setDatabaseName(“:memory:”);

db.setDatabaseName(":memory:");

3.创建表

SQL语句执行需要用到QSqlQuery类,文档有云:

QSqlQuery封装了在QSqlDatabase上执行的SQL查询中创建,导航和检索数据所涉及的功能。它可以被用来执行DML(数据操纵语言)语句,例如select、insert、update、delete,以及DDL(数据定义语言)语句,如create table,还可以用于执行非标准SQL的特定于数据库的命令。

成功执行的SQL语句将查询的状态设置为活动状态,以便isActive()返回true。否则,查询的状态将设置为非活动状态。在任何一种情况下,执行新的SQL语句时,查询都位于无效记录上。必须先将活动查询导航到有效记录(以便isActive()返回true),然后才能检索值。

#include <QSqlDatabase>
#include <QSqlError>
#include <QSqlQuery>

void createTable()
{
    //sql语句不熟悉的推荐《sql必知必会》,轻松入门
    //如果不存在则创建my_table表
    //id自增,name唯一
    const QString sql=R"(
                      CREATE TABLE IF NOT EXISTS  my_table (
                      id   INTEGER   PRIMARY KEY AUTOINCREMENT NOT NULL,
                      name CHAR (50) UNIQUE NOT NULL,
                      age  INTEGER
                      );)";
    //QSqlQuery构造前,需要db已打开并连接
    //未指定db或者db无效时使用默认连接进行操作
    QSqlQuery query;
    
    if(query.exec(sql)){
        qDebug()<<"init table success";
    }else{
        //打印sql语句错误信息
        qDebug()<<"init table error"<<query.lastError();
    }
}

代码通过QSqlQuery的exec方法执行SQL语句,创建了一个简单的数据表。exec执行SQL语句成功返回true,否则返回false。

QSqlQuery的构造函数可以指定QDatabase参数,如果未指定db,或者db无效将使用默认连接。

QSqlQuery::QSqlQuery(QSqlDatabase db);

要注意的是,对于SQLite,exec方法一次只能执行一个语句。 

4.执行增删改查

执行了上面的操作且数据库已open,就能使用QSqlQuery的exec方法来完成增删改查了。

//插入数据
void insertRecord(const QString &name, int age)
{
    QSqlQuery query;
    //方式一,直接执行SQL语句
    query.exec(QString(R"(INSERT INTO my_table(name,age) VALUES('%1',%2);)")
               .arg(name).arg(age));
    //方式二,绑定值,待定变量默认用问号占位,注意字符串也没有引号
    /*query.prepare(R"(INSERT INTO my_table(name,age) VALUES(?,?);)");
    query.addBindValue(name);
    query.addBindValue(age);
    query.exec();*/
}

//删除数据
void deleteRecord(const QString &name)
{
    QSqlQuery query;
    //方式一,直接执行SQL语句
    query.exec(QString(R"(DELETE FROM my_table WHERE name='%1';)")
               .arg(name));
    //方式二,绑定值,待定变量默认用问号占位
    /*query.prepare(R"(DELETE FROM my_table WHERE name=?;)");
    query.addBindValue(name);
    query.exec();*/
}

//更新数据
void updateRecord(const QString &name, int age)
{
    QSqlQuery query;
    //方式一,直接执行SQL语句
    query.exec(QString(R"(UPDATE my_table SET age=%2 WHERE name='%1';)")
               .arg(name).arg(age));
    //方式二,绑定值,待定变量默认问号,可自定义
    /*query.prepare(R"(UPDATE my_table SET age=:age WHERE name=:name;)");
    query.bindValue(":name",name);//通过自定义的别名来替代
    query.bindValue(":age",age);
    query.exec();*/
}

//查询数据
int searchRecord(const QString &name)
{
    QSqlQuery query;
    query.exec(QString(R"(SELECT age FROM my_table WHERE name='%1';)")
               .arg(name));

    //获取查询结果的第0个值,
    //如果结果是多行数据,可用while(query.next()){}遍历每一行
    int ageValue=-1;
    if(query.next()){
        ageValue=query.value(0).toInt();
    }
    qDebug()<<ageValue;
    return ageValue;
}

可以看到,如果熟悉SQL语句的话,很容易就实现了增删改查功能。 

对于 BLOB 类型,查询后可以 toByteArray,修改时可以 bindValue QByteArray。

5.进阶

有时候会遇到大量数据操作的情况,这时候用普通的insert之类的语句循环操作可能会很慢。

技巧一:开启事务

SQLite通过执行”BEGIN;“或是”BEGIN TRANSACTION;“开启事务,执行”ROLLBACK;“进行回滚,执行”COMMIT;“或是”END TRANSACTION;“提交事务。QSqlDatabase也提供了对应的transaction、rollback、commit三个函数来执行对应操作。

技巧二:关闭写同步(synchrnous)

在SQLite中,数据库配置的参数都由编译指示(pragma)来实现的,而其中synchronous选项有三种可选状态,分别是full、normal、off。简要说来,full写入速度最慢,但保证数据是安全的,不受断电、系统崩溃等影响,而off可以加速数据库的一些操作,但如果系统崩溃或断电,则数据库可能会损毁。通过执行”PRAGMA synchronous = OFF;“语句,可以提升效率,不过若不是临时数据库不建议此操作。

其他效率提升见参考博客。

(2021-1-24补充)多线程操作:

(对如多线程建立连接,参照 https://gongjianbo1992.blog.csdn.net/article/details/105518870 )

SQLite 默认是文件锁, Qt 中 SQLite 默认是以多线程读写模式打开,如果同时写入就会出现写入错误:

Qt中操作SQLite数据库

可以将写操作上锁,但是实测线程中循环写入时,只读打开去查询也是会阻塞很久,毫秒到几秒不等,这时候就得把超时设置长一点。

Qt中操作SQLite数据库

所以还是得读写都加锁,但这也只能解决单个进程的并发访问。

6.工具

两个轻量的 SQLite 可视化工具,都提供了免安装版本:

SQLite Studio(可以在Tool->Config->Look设置简体中文但是新版有些地方没翻译,打开db后别的程序也可以正常操作该db):https://sqlitestudio.pl/

DB Browser For SQLite(有中文翻译,但是打开db后别程序的无法操作该db):http://www.sqlitebrowser.org/dl/

7.参考

文档:https://doc.qt.io/qt-5/qsqldatabase.html

博客:https://www.cnblogs.com/xia-weiwen/archive/2017/05/04/6806709.html

博客:http://blog.sina.com.cn/s/blog_a6fb6cc90101gx30.html

SQLite教程:http://www.runoob.com/sqlite/sqlite-tutorial.html

SQLite优化:https://www.cnblogs.com/zzyyxxjc/p/7495279.html

SQLite优化:https://www.cnblogs.com/huozhong/p/5973938.html

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/234162.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • 1bit等于多少字节,换算方法??[通俗易懂]

    1bit等于多少字节,换算方法??[通俗易懂]1比特(bit)=0.125字节(b)1B就是1个字节。Byte、KB、B、MB、GB之间的关系是:Bit——比特B——字节KB——千字节MB——兆字节GB——吉字节TB——太字节1B=8Bit计算机64位的=8个字节…

  • 详解Linux双网卡绑定之bond0「建议收藏」

    1、什么是bond?  网卡bond是通过多张网卡绑定为一个逻辑网卡,实现本地网卡的冗余,带宽扩容和负载均衡,在生产场景中是一种常用的技术。Kernels2.4.12及以后的版本均供bonding模块,以前的版本可以通过patch实现。2、实现原理:  网卡工作在混杂(promisc)模式,接收到达网卡的所有数据包,tcpdump工作用的也是混杂模式(promisc),将两块网卡的MAC地址…

  • IDEA优化内存配置,可提高启动和运行速度(亲测有效)「建议收藏」

    IDEA优化内存配置,可提高启动和运行速度(亲测有效)「建议收藏」一、优化IDEA配置IDEA默认启动配置主要考虑低配置用户,参数不高(默认最低128m,最高512m),导致启动慢,然后运行也不流畅,这里我们需要优化下启动和运行配置;但是在工作中的电脑一般都是8G或者16G的运行内存,所以我们需要手动去修改默认的IDEA配置。二、手动修改IDEA配置步骤找到IDEA安装的bin目录打开idea.exe.vmoptions文件关键的三个参…

  • web服务器状态码(服务端500错误码)

    对于第304页的错误,一直是SEO工作人员老生常谈的话题。初始网站管理员对304错误非常敏感。互联网上总是有与之相关的新闻,比如:大量的304状态码会在网站上被降级,但这是真的吗?一、304错误提示是什么意思?简单理解:网站304的错误状态代码是当客户端试图访问服务器互相的信息提示。如果第二次访问期间页面内容没有更改,服务器将返回304状态代码。严格来说,这不是一个错误。值得注意的是,通过网站的日…

  • c++ set集合的使用方法详解

    c++ set集合的使用方法详解set集合是c++stl库中自带的一个容器,set具有以下两个特点:1、set中的元素都是排好序的2、set集合中没有重复的元素常用操作:begin()  返回set容器的第一个元素的地址end()    返回set容器的最后一个元素地址clear()  删除set容器中的所有的元素empty()   判断set容器是否为空max_size()

  • vim为什么不能打开文件了(vim怎么保存文件)

    vim打开的文件无法使用:wq保存的问题在使用vim编辑一个.c文件的时候,完成使用:wq保存报以下错误网上查了一下,应该是权限问题.一般做法是先退出当前vim,以sudovim进入即可。如果使用ctrl+z命令退出,授予权限之后无法使用fg命令返回vim中E121:无法打开并写入文件解决办法1、使用命令:w!sudotee%保存即可。其中:冒号(:)表示我们处于vim的退出模式;感叹号(!)表示我们正在运行shell命令;sudo和tee都是shell命令;%表示从当前

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号