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

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

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

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • Activiti教程二

    Activiti教程二一搭建环境1.1JDK6+1.2Ant1.8.1+1.3Eclipse3.7+1.4Activiti-eclipsedesigner插件安装1.4.1先安装GEF插件1.4.2安装SVN插件1.4.3安装Maven插件1.4.4最后安装Activiti-eclipsedesigner二开始activiti5.12.1的第一个demo

    2022年7月21日
    20
  • ARM机器使用netdata监控

    ARM机器使用netdata监控ARM 机器使用 netdata 监控安装下载地址 https github com netdata netdata releases 找到对应平台的版本下载此处使用了 netdata aarch64 latest gz run 下载下来直接 shnetdata aarch64 latest gz run 进行安装 安装完成之后 可以通过在浏览器中访问 http your server ip 19999 查看 Netdata 的监控 如果不可以查看 请查看防火墙设置 查看状态 停止 重启 systemc

    2025年6月23日
    4
  • linux内核 lock free

    linux内核 lock free//同步问题:对共享数据的访问,需要同步,互斥。在中断,抢占,多CPU,多线程环境下尤其重要。 同步分为: 阻塞同步,非阻塞同步阻塞同步有许多实现方式了:mutex,semaphore.阻塞同步使用不当就可能造成死锁,活锁,优先级反转。非阻塞同步:(现在流行三种) waitfree 很难实现,思想是本线程有限步就完成,完全不用理其余线程。 lock

    2022年7月19日
    17
  • 数据库的数据模型是网状模型_网状模型的数据结构是

    数据库的数据模型是网状模型_网状模型的数据结构是层次数据模型    定义:层次数据模型是用树状<层次>结构来组织数据的数据模型。    满足下面两个条件的基本层次联系的集合为层次模型    1.有且只有一个结点没有双亲结点,这个结点称为根结点    2.根以外的其它结点有且只有一个双亲结点其实层次数据模型就是的图形表示就是一个倒立生长的树,由基本数据结构中的树(或者二叉树)的定义可知,每棵树都有且仅有一个根节点,其余的…

    2025年6月28日
    6
  • oracle 修改表名

    oracle 修改表名ALTER TABLE AA RENAME TO BB;

    2022年5月13日
    40
  • GRE over IPsec && IPsec over GRE

    GRE over IPsec && IPsec over GRE

    2021年8月18日
    49

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

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