9、QT—SQLite使用小记

news2025/1/17 23:14:33

前言
开发平台:Win10 64位
开发环境:Qt Creator 13.0.0
构建环境:Qt 5.15.2 +MSVC2019 64位
sqlite版本:sqlite3


文章目录

  • 一、Sqlite是什么
  • 二、sqlite使用步骤
    • 2.1 下载
    • 2.2 安装
    • 2.3 使用
  • 三、Qt集成sqlite3
    • 3.1 关键问题
    • 3.2 封装sqlite
  • 四、参考文献
    • 4.1 https://blog.csdn.net/Javachichi/article/details/138106632
    • 4.2 https://zhuanlan.zhihu.com/p/24993071
    • 4.3 https://blog.csdn.net/weixin_50670076/article/details/136350060
    • 4.4 https://www.cnblogs.com/sfy5848/p/4825771.html
    • 4.5 https://blog.csdn.net/only_a_Heroic_car/article/details/119605906
    • 4.6 https://blog.csdn.net/p154613730/article/details/85144718
    • 4.7 https://blog.csdn.net/lms1008611/article/details/81271712


一、Sqlite是什么

SQLite 是一个用 C 语言编写的开源、轻量级、快速、独立且高可靠性的 SQL 数据库引擎,它提供了功能齐全的数据库解决方案。SQLite 几乎可以在所有的手机和计算机上运行,它被嵌入到无数人每天都在使用的众多应用程序中。
此外,SQLite 还具有稳定的文件格式、跨平台能力和向后兼容性等特点。SQLite 的开发者承诺,至少在 2050 年之前保持该文件格式不变。

二、sqlite使用步骤

2.1 下载

官方下载地址: link
在这里插入图片描述
windows平台下载这个预编译的就可以。从后面解释可以看到,压缩包里面是一些命令行工具,用来管理sqlite数据库的。

2.2 安装

下载完后解压得到三个文件,都是用来执行命令行工具的可执行应用。
在这里插入图片描述

  1. sqldiff.exe: 命令行实用程序,用于显示 SQLite 数据库之间的内容差异
  2. sqlite3.exe:命令行实用程序,执行 SQLite 数据库操作和 SQL 语句。
  3. sqlite3_analyzer.exe:命令行实用程序,测量和显示多少和如何有效的空间被用于单个的表和索引与SQLite数据库文件

配置环境变量: 为了在命令提示符或 PowerShell 中从任何地方运行 SQLite,需要将 SQLite 的路径添加到电脑的 PATH 环境变量中。

  • 打开控制面板并选择 “系统”。
  • 点击 “高级系统设置”。
  • 在 “系统属性” 对话框中,点击 “环境变量” 按钮。
  • 在 “系统变量” 部分,滚动找到并选中 “Path”,然后点击 “编辑”。
  • 在 “编辑环境变量” 对话框中,点击 “新建”,然后输入您的 SQLite 目录的路径,比如 C:\sqlite-tools-win-x64-3450300。
  • 点击 “确定” 保存更改。

测试安装: win+r打开一个新的命令提示符或 PowerShell 窗口,并输入 sqlite3。如果您看到了 SQLite 的欢迎消息和一个命令提示符,那么说明您已经成功安装了 SQLite。其实这一步和双击sqlite3.exe实现的功能是一样的,都是调用命令行,只不过可以省去双击sqlite3.exe这一步。
在这里插入图片描述


2.3 使用

根据提示输入.help,获取命令功能提示

C:\Users\qwer>sqlite3
SQLite version 3.45.3 2024-04-15 13:34:05 (UTF-16 console I/O)
Enter ".help" for usage hints.
Connected to a transient in-memory database.
Use ".open FILENAME" to reopen on a persistent database.
sqlite> .help
.archive ...             Manage SQL archives
.auth ON|OFF             Show authorizer callbacks
.backup ?DB? FILE        Backup DB (default "main") to FILE
.bail on|off             Stop after hitting an error.  Default OFF
.cd DIRECTORY            Change the working directory to DIRECTORY
.changes on|off          Show number of rows changed by SQL
.check GLOB              Fail if output since .testcase does not match
.clone NEWDB             Clone data into NEWDB from the existing database
.connection [close] [#]  Open or close an auxiliary database connection
.crnl on|off             Translate \n to \r\n.  Default ON
.databases               List names and files of attached databases
.dbconfig ?op? ?val?     List or change sqlite3_db_config() options
.dbinfo ?DB?             Show status information about the database
.dump ?OBJECTS?          Render database content as SQL
.echo on|off             Turn command echo on or off
.eqp on|off|full|...     Enable or disable automatic EXPLAIN QUERY PLAN
.excel                   Display the output of next command in spreadsheet
.exit ?CODE?             Exit this program with return-code CODE
.expert                  EXPERIMENTAL. Suggest indexes for queries
.explain ?on|off|auto?   Change the EXPLAIN formatting mode.  Default: auto
.filectrl CMD ...        Run various sqlite3_file_control() operations
.fullschema ?--indent?   Show schema and the content of sqlite_stat tables
.headers on|off          Turn display of headers on or off
.help ?-all? ?PATTERN?   Show help text for PATTERN
.import FILE TABLE       Import data from FILE into TABLE
.indexes ?TABLE?         Show names of indexes
.limit ?LIMIT? ?VAL?     Display or change the value of an SQLITE_LIMIT
.lint OPTIONS            Report potential schema issues.
.load FILE ?ENTRY?       Load an extension library
.log FILE|on|off         Turn logging on or off.  FILE can be stderr/stdout
.mode MODE ?OPTIONS?     Set output mode
.nonce STRING            Suspend safe mode for one command if nonce matches
.nullvalue STRING        Use STRING in place of NULL values
.once ?OPTIONS? ?FILE?   Output for the next SQL command only to FILE
.open ?OPTIONS? ?FILE?   Close existing database and reopen FILE
.output ?FILE?           Send output to FILE or stdout if FILE is omitted
.parameter CMD ...       Manage SQL parameter bindings
.print STRING...         Print literal STRING
.progress N              Invoke progress handler after every N opcodes
.prompt MAIN CONTINUE    Replace the standard prompts
.quit                    Stop interpreting input stream, exit if primary.
.read FILE               Read input from FILE or command output
.recover                 Recover as much data as possible from corrupt db.
.restore ?DB? FILE       Restore content of DB (default "main") from FILE
.save ?OPTIONS? FILE     Write database to FILE (an alias for .backup ...)
.scanstats on|off|est    Turn sqlite3_stmt_scanstatus() metrics on or off
.schema ?PATTERN?        Show the CREATE statements matching PATTERN
.separator COL ?ROW?     Change the column and row separators
.session ?NAME? CMD ...  Create or control sessions
.sha3sum ...             Compute a SHA3 hash of database content
.shell CMD ARGS...       Run CMD ARGS... in a system shell
.show                    Show the current values for various settings
.stats ?ARG?             Show stats or turn stats on or off
.system CMD ARGS...      Run CMD ARGS... in a system shell
.tables ?TABLE?          List names of tables matching LIKE pattern TABLE
.timeout MS              Try opening locked tables for MS milliseconds
.timer on|off            Turn SQL timer on or off
.trace ?OPTIONS?         Output each SQL statement as it is run
.version                 Show source, library and compiler versions
.vfsinfo ?AUX?           Information about the top-level VFS
.vfslist                 List all available VFSes
.vfsname ?AUX?           Print the name of the VFS stack
.width NUM1 NUM2 ...     Set minimum column widths for columnar output
sqlite>
  • SQLite 新建数据库
    直接执行 .open filename.db 打开或创建一个 SQLite 数据库。如果文件不存在,SQLite 会自动创建它。
    示例:打开或创建名为 test.db 的 SQLite 数据库文件。
sqlite> .open test.db

只要创建个数据库就可以了,下面创建表及其其他操作,在可视化工具中执行就可以,笔者使用navicat来操作。navicat的安装使用教程科查看参考文献4.3。


三、Qt集成sqlite3

Qt5以上版本可以直接使用SQLite(Qt自带驱动)。

3.1 关键问题

首先需要一个驱动,就是QSqlDatabase,这个类是管理整个数据库的核心,另外一个是关键类是QSqlQuery,用来对数据库内容增删改查的。
在使用之前要明确几个问题

  1. 数据库,可以直接生成一个数据库吗?还是需要先创建一个数据库再使用?
  2. 数据库的位置:如果使用已经存在的数据库,这个数据库放在哪里?同exe同一个文件夹?如果自动生成,生成在哪里?同exe同一个文件夹?
  3. 哪些函数来生成数据库、打开数据库、表的操作、增删改查的操作?
    首先回答下第一个问题:可以在程序中自动生成一个数据库,不用通过上面第二节中讲的先创建一个数据库,因为Qt已经添加了sqlite驱动就是QSqlDatabase类。
    第二个问题:如果使用默认的方式,需要将数据库放在exe文件的上一级目录中,因为程序会在这个目录中找有没有这个数据库,如果没有,那就在这个目录下自动创建一个,如果有,那就使用这个数据库。
    当然可以自定义数据库的位置,那么程序就会去这个自定义路径下去找或者自动生成数据库。
    在这里插入图片描述
    第三个问题:主要的函数有下面几个
    1)QSqlDatabase QSqlDatabase::addDatabase((const QString & type, const QString & connectionName = QLatin1String( defaultConnection )
    这个就是数据库生成对象,这里面的参数一个是数据库类型,就是使用的什么数据库,第二个参数就是自定义一个连接名,就是要告诉QSqlDatabase咱们定个名,这样你使用这个名的时候QSqlDatabase知道去操作那个数据库。
    这个返回的类型是QSqlDatabase,就是一个数据库实例,有了他就有权利去操作数据库的生成删除,开启关闭了。
    在这里插入图片描述
    在这里插入图片描述
    2)void QSqlDatabase::setDatabaseName ( const QString & name ),这个函数就是设置数据库的函数,它是可以自动生成数据库的,取决于参数中的这个东西他找不找得到,如果找不到就会按规则自动生成。
    这里的参数形式笔者举个例来说明下,比如有一个test.db的数据库,那么调用的时候可以这样
setDatabaseName("test.db")

这里一定要带后缀名,这样,程序会在上面我们说的默认路径下即exe文件的上一级目录中搜索这个数据库,如果找到了,那就直接用,如果没找到,那就创建一个同名的数据库。
第二个问题就是我们想自定义这个数据库的路径(不管已存在还是未存在的),那就需要这样

setDatabaseName("c:\\databases\\test.db")

这样程序就会去我们给的这个路径中去找,找到使用,找不到,在这个路径下生成同名数据库。
在这里插入图片描述
3)void QSqlDatabase::removeDatabase ( const QString & connectionName ) [static]
在这里插入图片描述

3.2 封装sqlite

上面一小节说明了创建打开数据库,下面把封装好的头文件和源文件贴下

#ifndef SQLITEHELPER_H
#define SQLITEHELPER_H
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QHash>
#include <QString>
#include <QVariant>

class SqliteHelper
{
public:
    SqliteHelper();
    ///
    /// \brief OpenSqlite 打开数据库
    /// \param dbName 数据库名
    /// \param connectName 连接名
    /// \return
    ///
    bool OpenSqlite(const QString &dbName,const QString &connectName);
    ///
    /// \brief CloseSqlite 关闭数据库
    /// \return
    ///
    void CloseSqlite();

    /**
     * @brief getConnectName 获取连接名
     * @return
     */
    QString getConnectName() const;

    /**
     * @brief isExistTable 判断数据表是否存在
     * @param tableName 数据表名
     * @return
     */
    bool isExistTable(const QString &tableName);

    /**
     * @brief createTable 创建数据表
     * @param tableName 数据表名
     * @param fields 字段(字段名和类型,如{"name", "varchar(5)"})
     * @param pks 主键
     * @return
     */
    bool createTable(const QString &tableName, const QHash<QString, QString> &fields, const QList<QString> &pks);

    /**
     * @brief selectData 选择数据(适用于单表选择)
     * @param tableName 数据表名
     * @param fields 选择字段
     * @param data [OUT]数据(按fields的顺序)
     * @return
     */
    bool selectData(const QString &tableName, const QList<QString> &fields, QList<QVariantList> &data);

    /**
     * @brief selectData 选择数据(适用于单表选择)
     * @param tableName 数据表名
     * @param fields 选择字段
     * @param whereConditions where条件
     * @param data [OUT]数据(按fields的顺序)
     * @return
     */
    bool selectData(const QString &tableName, const QList<QString> &fields, const QHash<QString, QVariant> &whereConditions,
                    QList<QVariantList> &data);

    /**
     * @brief selectDataBySql 选择数据(通过sql查询, 多表联合查询)
     * @param sql select语句
     * @param fields 选择字段
     * @param data [OUT]数据(按fields的顺序)
     * @return
     */
    bool selectDataBySql(const QString &sql, const QList<QString> &fields, QList<QVariantList> &data);

    /**
     * @brief insertRowData 插入行数据
     * @param tableName 数据表名
     * @param fields 插入字段
     * @param data 插入数据(数据与字段的顺序需一致)
     * @return
     */
    bool insertRowData(const QString &tableName, const QList<QString> &fields, const QVariantList &data);

    /**
     * @brief insertRowsData 插入多行数据
     * @param tableName 数据表名
     * @param fields 字段
     * @param data 插入数据(数据与字段的顺序需一致)
     * @return
     */
    bool insertRowsData(const QString &tableName, const QList<QString> &fields, const QList<QVariantList> &data);

    /**
     * @brief updateData 更新数据
     * @param tableName 数据表名
     * @param data 更新的字段数据(字段名和值,如{"age", 27})
     * @param whereConditions where条件(字段名和值,如{"age", 27})
     * @return
     */
    bool updateData(const QString &tableName, const QHash<QString, QVariant> &data,
                    const QHash<QString, QVariant> &whereConditions);

    /**
     * @brief deleteData 删除数据
     * @param tableName 数据表名
     * @param whereConditions where条件(字段名和值,如{"age", 27})
     * @return
     */
    bool deleteData(const QString &tableName, const QHash<QString, QVariant> &whereConditions);

    /**
     * @brief exec 执行sql语句
     * @param sql sql语句
     * @return 执行结果
     */
    bool exec(const QString &sql);

    /**
     * @brief hasTransactions 是否支持事务
     * @return
     */
    bool hasTransactions();

    /**
     * @brief transaction 开启事务
     * @return
     */
    bool transaction();

    /**
     * @brief commit 事务提交
     * @return
     */
    bool commit();

    /**
     * @brief rollback 事务回滚
     * @return
     */
    bool rollback();

    /**
     * @brief size 记录数量(在执行select语句后,可用该函数获取select的大小)
     * @return
     */
    int size();

    /**
     * @brief getTableFieldsInfo 获取数据表字段
     * @param tableName 数据表名
     * @param fieldsName [OUT]字段
     * @return
     */
    bool getTableFieldsInfo(const QString &tableName, QList<QString> &fieldsName);

    /**
     * @brief lastQuerySql 获取最新一次执行的sql语句
     * @return
     */
    QString lastQuerySql();

    /**
     * @brief lastError 获取最新的错误信息
     * @return 错误信息
     */
    QString lastError() const;

private:
    /**
     * @brief checkTableInfo 校验数据表信息(数据表和字段是否存在)
     * @param tableName 数据表名
     * @param fields 字段
     * @return
     */
    bool checkTableInfo(const QString &tableName, const QList<QString> &fields);


protected:
    QSqlDatabase sqlDb;
    QString m_connectName;
    QSqlQuery m_query;
    QString m_lastError;
};

#endif // SQLITEHELPER_H


#include "sqlitehelper.h"
#include <QDebug>
#include <QSqlError>
#include <QSqlDriver>
//240522 这个构造函数会被引用的时候实例化
SqliteHelper::SqliteHelper() {
    
}

bool SqliteHelper::OpenSqlite(const QString &dbName, const QString &connectName)
{   
    //QPSQL为数据库类型,OTHER为连接名。
    if (QSqlDatabase::connectionNames().contains(connectName)) {
        //240522 返回一个对象实例,并将值复制给sqlDb

        sqlDb = QSqlDatabase::database(connectName);
    } else {
         
        sqlDb = QSqlDatabase::addDatabase("QSQLITE", connectName);
    }

    m_connectName = connectName;

    if (sqlDb.isOpen()) {
        sqlDb.close();
    }
    //240522 设置数据库名称,这个名称可以是数据库名,也可以是数据库所在的路径
    sqlDb.setDatabaseName(dbName);
    if (sqlDb.open()) {
        m_query = QSqlQuery(sqlDb);
        return true;
    }

    m_lastError = sqlDb.lastError().text();
    return false;
}

void SqliteHelper::CloseSqlite()
{
    sqlDb.close();
}

QString SqliteHelper::getConnectName() const
{
    return m_connectName;
}

bool SqliteHelper::isExistTable(const QString &tableName)
{
    return sqlDb.tables().contains(tableName);
}

///
/// \brief SqliteHelper::createTable 创建表
/// \param tableName 表名
/// \param fields 字段
/// \param pks 主键
/// \return
///
bool SqliteHelper::createTable(const QString &tableName, const QHash<QString, QString> &fields,
                               const QList<QString> &pks)
{
    //如果存在就返回
    if (isExistTable(tableName)) {
        m_lastError = QString("Table [%1] is already exist").arg(tableName);
        return false;
    }

    //不存在,开始拼接字符串
    QString sql = QString("create table %1 (").arg(tableName);

    for (auto iter = fields.begin(); iter != fields.end(); ++iter) {
        sql.append(QString("%1 %2, ").arg(iter.key(), iter.value()));
    }

    sql.append(QString("primary key ("));
    qDebug()<<sql;
    for (const auto &item : pks) {
        sql.append(QString("%1, ").arg(item));
    }
    qDebug()<<sql;
    sql.remove(sql.length() - 2, 2);
    sql.append("))");
    qDebug()<<sql;
    if (m_query.exec(sql)) {
        return true;
    }

    m_lastError = m_query.lastError().text();
    return false;
}

bool SqliteHelper::selectData(const QString &tableName, const QList<QString> &fields, QList<QVariantList> &data)
{
    if (!checkTableInfo(tableName, fields)) {
        return false;
    }

    QString sql = QString("select ");
    for (const auto &item : fields) {
        sql.append(QString("%1, ").arg(item));
    }
    sql.remove(sql.length() - 2, 2);
    sql.append(QString(" from %1").arg(tableName));

    if (m_query.exec(sql)) {
        while (m_query.next()) {
            QVariantList temp;
            for (const auto &item : fields) {
                temp.append(m_query.value(item));
            }
            data.append(temp);
        }
        return true;
    }

    m_lastError = m_query.lastError().text();
    return false;
}

bool SqliteHelper::selectData(const QString &tableName, const QList<QString> &fields,
                             const QHash<QString, QVariant> &whereConditions, QList<QVariantList> &data)
{
    QList<QString> tempFields;
    tempFields.append(fields);
    tempFields.append(whereConditions.keys());
    if (!checkTableInfo(tableName, tempFields)) {
        return false;
    }

    QString sql = QString("select ");
    for (const auto &item : fields) {
        sql.append(QString("%1, ").arg(item));
    }
    sql.remove(sql.length() - 2, 2);
    sql.append(QString(" from %1").arg(tableName));

    sql.append(QString(" where "));
    for (auto iter = whereConditions.begin(); iter != whereConditions.end(); ++iter) {
        sql.append(QString("%1 = ? and ").arg(iter.key()));
    }
    sql.remove(sql.length() - 5, 5);

    m_query.prepare(sql);
    for (auto iter = whereConditions.begin(); iter != whereConditions.end(); ++iter) {
        m_query.addBindValue(iter.value());
    }

    if (m_query.exec()) {
        while (m_query.next()) {
            QVariantList temp;
            for (const auto &item : fields) {
                temp.append(m_query.value(item));
            }
            data.append(temp);
        }
        return true;
    }

    m_lastError = m_query.lastError().text();
    return false;
}

bool SqliteHelper::selectDataBySql(const QString &sql, const QList<QString> &fields, QList<QVariantList> &data)
{
    if (m_query.exec(sql)) {
        while (m_query.next()) {
            QVariantList temp;
            for (const auto &item : fields) {
                temp.append(m_query.value(item));
            }
            data.append(temp);
        }
        return true;
    }

    m_lastError = m_query.lastError().text();
    return false;
}

bool SqliteHelper::insertRowData(const QString &tableName, const QList<QString> &fields, const QVariantList &data)
{
    if (!checkTableInfo(tableName, fields)) {
        return false;
    }

    QString sql = QString("insert into %1(").arg(tableName);
    for (const auto &item : fields) {
        sql.append(QString("%1, ").arg(item));
    }
    sql.remove(sql.length() - 2, 2);
    sql.append(QString(") values"));

    QString tempValue = QString("(");
    for (int i = 0; i < fields.count(); ++i) {
        tempValue.append(QString("?, "));
    }
    tempValue.remove(tempValue.length() - 2, 2);
    tempValue.append(QString(")"));

    sql.append(tempValue);

    m_query.prepare(sql);

    for (int i = 0; i < fields.count(); ++i) {
        m_query.addBindValue(data.at(i));
    }


    if (m_query.exec()) {
        return true;
    }

    m_lastError = m_query.lastError().text();
    return false;
}

bool SqliteHelper::insertRowsData(const QString &tableName, const QList<QString> &fields, const QList<QVariantList> &data)
{
    if (!checkTableInfo(tableName, fields)) {
        return false;
    }

    QString sql = QString("insert into %1(").arg(tableName);
    for (const auto &item : fields) {
        sql.append(QString("%1, ").arg(item));
    }
    sql.remove(sql.length() - 2, 2);
    sql.append(QString(") values"));

    QString tempValue = QString("(");
    for (int i = 0; i < fields.count(); ++i) {
        tempValue.append(QString("?, "));
    }
    tempValue.remove(tempValue.length() - 2, 2);
    tempValue.append(QString(")"));

    for (int i = 0; i < data.count(); ++i) {
        sql.append(QString("%1, ").arg(tempValue));
    }
    sql.remove(sql.length() - 2, 2);

    m_query.prepare(sql);
    for (const auto &item : data) {
        for (int i = 0; i < fields.count(); ++i) {
            m_query.addBindValue(item.at(i));
        }
    }

    if (m_query.exec()) {
        return true;
    }

    m_lastError = m_query.lastError().text();
    return false;
}

bool SqliteHelper::updateData(const QString &tableName, const QHash<QString, QVariant> &data,
                             const QHash<QString, QVariant> &whereConditions)
{
    QList<QString> fields;
    fields << data.keys() << whereConditions.keys();
    if (!checkTableInfo(tableName, fields)) {
        return false;
    }

    QString sql = QString("update %1 set ").arg(tableName);
    for (auto iter = data.begin(); iter != data.end(); ++iter) {
        sql.append(QString("%1 = ?, ").arg(iter.key()));
    }
    sql.remove(sql.length() - 2, 2);

    sql.append(" where ");
    for (auto iter = whereConditions.begin(); iter != whereConditions.end(); ++iter) {
        sql.append(QString("%1 = ? and ").arg(iter.key()));
    }
    sql.remove(sql.length() - 5, 5);

    m_query.prepare(sql);
    for (auto iter = data.begin(); iter != data.end(); ++iter) {
        m_query.addBindValue(iter.value());
    }
    for (auto iter = whereConditions.begin(); iter != whereConditions.end(); ++iter) {
        m_query.addBindValue(iter.value());
    }

    if (m_query.exec()) {
        return true;
    }

    m_lastError = m_query.lastError().text();
    return false;
}

bool SqliteHelper::deleteData(const QString &tableName, const QHash<QString, QVariant> &whereConditions)
{
    QList<QString> fields = whereConditions.keys();
    if (!checkTableInfo(tableName, fields)) {
        return false;
    }

    QString sql = QString("delete from %1 where ").arg(tableName);
    for (auto iter = whereConditions.begin(); iter != whereConditions.end(); ++iter) {
        sql.append(QString("%1 = ? and ").arg(iter.key()));
    }
    sql.remove(sql.length() - 5, 5);

    m_query.prepare(sql);
    for (auto iter = whereConditions.begin(); iter != whereConditions.end(); ++iter) {
        m_query.addBindValue(iter.value());
    }

    if (m_query.exec()) {
        return true;
    }

    m_lastError = m_query.lastError().text();
    return false;
}

bool SqliteHelper::exec(const QString &sql)
{
    if (m_query.exec(sql)) {
        return true;
    }

    m_lastError = m_query.lastError().text();
    return false;
}

bool SqliteHelper::hasTransactions()
{
    if (m_query.driver()->hasFeature(QSqlDriver::Transactions)) {
        return true;
    }

    m_lastError = QString("This database don't support tasnsactions");
    return false;
}

bool SqliteHelper::transaction()
{
    return sqlDb.transaction();
}

bool SqliteHelper::commit()
{
    return sqlDb.commit();
}

bool SqliteHelper::rollback()
{
    return sqlDb.rollback();
}

int SqliteHelper::size()
{
    int count = -1;
    m_query.first();
    if (m_query.next()) {
        if (m_query.driver()->hasFeature(QSqlDriver::QuerySize)) {
            count = m_query.size();
        } else {
            m_query.last();
            // m_query.at()是返回当前记录的编号(从0开始),所以最后一条记录的编号 +1 就为记录数
            count = m_query.at() + 1;
        }
    }

    m_query.first();
    return count;
}

bool SqliteHelper::getTableFieldsInfo(const QString &tableName, QList<QString> &fieldsName)
{
    QString sql = QString("PRAGMA table_info('%1')").arg(tableName);
    if (m_query.exec(sql)) {
        while (m_query.next()) {
            fieldsName.append(m_query.value(1).toString());
        }
        return true;
    }

    m_lastError = m_query.lastError().text();
    return false;
}

QString SqliteHelper::lastQuerySql()
{
    return m_query.lastQuery();
}

QString SqliteHelper::lastError() const
{
    return m_lastError;
}

bool SqliteHelper::checkTableInfo(const QString &tableName, const QList<QString> &fields)
{
    if (!isExistTable(tableName)) {
        m_lastError = QString("Table [%1] is not exist").arg(tableName);
        return false;
    }

    QList<QString> fieldsName;
    QStringList noFieldsName;
    if (getTableFieldsInfo(tableName, fieldsName)) {
        for (const auto &item : fields) {
            if (!fieldsName.contains(item)) {
                noFieldsName << item;
            }
        }

        if (noFieldsName.count() > 0) {
            m_lastError = QString("Table [%1] have no fields [%2]").arg(tableName).arg(noFieldsName.join(','));
            return false;
        }
    } else {
        return false;
    }

    return true;
}

四、参考文献

4.1 https://blog.csdn.net/Javachichi/article/details/138106632

4.2 https://zhuanlan.zhihu.com/p/24993071

4.3 https://blog.csdn.net/weixin_50670076/article/details/136350060

4.4 https://www.cnblogs.com/sfy5848/p/4825771.html

4.5 https://blog.csdn.net/only_a_Heroic_car/article/details/119605906

4.6 https://blog.csdn.net/p154613730/article/details/85144718

4.7 https://blog.csdn.net/lms1008611/article/details/81271712

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

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

相关文章

JAVA开发 基础Jaccard来计算两个字符串之间的重复率

计算两个字符串之间的重复率 Jaccard实现代码基于最长公共子序列来计算两个字符串之间的重复率 Jaccard Jaccard方法&#xff0c;也称为Jaccard相似度或Jaccard相似系数&#xff0c;是一种用于衡量两个集合相似程度的指标。其逻辑基于集合之间的交集与并集的关系来衡量它们的相…

5.23-

回顾 I0多路复用的原理? 程序首先向操作系统发起一个IO多路复用请求&#xff0c;告诉操作系统需要监视哪些IO通道。这些IO通道可以包括网络套接字、文件描述符等操作系统随后会将这些IO通道放入一个队列中&#xff0c;并在某个IO通道就绪时&#xff08;如数据到达、文件可读…

Aws EC2 + Aws Cli + Terraform

1 什么是 Terraform&#xff1f; Terraform 是由 HashiCorp 创建的“基础架构即代码”(Infrastructure-as-Code&#xff0c;IaC)开源工具。Terraform 的配置语言是 HashiCorp Configuration Language&#xff08;HCL&#xff09;&#xff0c;用来替代更加冗长的 JSON 和 XML 等…

7---Linux调试器gdb及拓展知识

一、先决知识补充&#xff1a; 1.1为什么测试人员需要测试的版本必须是release版本而不是debug版本&#xff1f; release版本是用户使用到的版本&#xff0c;release版本能够提供更真实的性能表现、完整的代码逻辑、安全性、稳定性以及用户体验。测试release版本可以确保用户…

基于深度学习PET/CT放射学的预后价值:未来在晚期鼻咽癌个体化诱导化疗中的潜在作用 | 文献速递-深度学习结合影像组学

Title 题目 Prognostic Value of Deep Learning PET/CT-BasedRadiomics: Potential Role for Future IndividualInduction Chemotherapy in AdvancedNasopharyngeal Carcinoma 基于深度学习PET/CT放射学的预后价值&#xff1a;未来在晚期鼻咽癌个体化诱导化疗中的潜在作用 0…

Android 逆向学习【2】——APK基本结构

APK安装在安卓机器上的&#xff0c;相当于就是windows的exe文件 APK实际上是个压缩包 只要是压缩的东西 .jar也是压缩包 里面是.class(java编译后的一些东西) APK是Android Package的缩写,即Android安装包。而apk文件其实就是一个压缩包&#xff0c;我们可以将apk文件的后…

【McCabe度量法】方法详解和软考历年真题

&#x1f50e;嘿&#xff0c;这里是慰慰&#x1f469;&#x1f3fb;‍&#x1f393;&#xff0c;会发各种类型的文章&#xff0c;智能专业&#xff0c;从事前端&#x1f43e; &#x1f389;如果有帮助的话&#xff0c;就点个赞叭&#xff0c;让我开心一下&#xff01;&#x1f…

slam14讲(第9,10讲 后端)

slam14讲&#xff08;第9&#xff0c;10讲 后端&#xff09; 后端分类基于滤波器的后端线性系统和卡尔曼滤波非线性系统和扩展卡尔曼滤波 BA优化H矩阵的稀疏性和边缘化H矩阵求解的总结 位姿图优化公式推导 基于滑动窗口的后端个人见解旧关键帧的边缘化 后端分类 基于滤波器的后…

Linux-文件或目录权限

在使用 ll 时&#xff0c;可以查看文件夹内容的详细信息&#xff0c;信息的第1位表示类型&#xff0c;具体信息如下&#xff1a; 类型说明-普通文件d文件夹b块设备文件c字符设备文件p管道文件s套接口文件 第2-10位表示权限&#xff0c; 举例&#xff1a;rwxr-xr-x 类型说明r…

Golang | Leetcode Golang题解之第97题交错字符串

题目&#xff1a; 题解&#xff1a; func isInterleave(s1 string, s2 string, s3 string) bool {n, m, t : len(s1), len(s2), len(s3)if (n m) ! t {return false}f : make([]bool, m 1)f[0] truefor i : 0; i < n; i {for j : 0; j < m; j {p : i j - 1if i >…

mysql误删后使用binlog恢复数据

1 预期效果 使用 binlog 恢复数据的预期效果是将误删的数据还原到误删之前的状态&#xff0c;以减少或消除数据丢失的影响。通过正确解析和执行 binlog 中的操作记录&#xff0c;可以重新执行误删操作之后的插入、更新或删除操作&#xff0c;从而恢复被误删的数据。 数据恢复&…

二.Flowable自带Demo(Flowable-UI)体验

问题反馈 如有问题可通过微信公众号“假装正经的程序员”反馈 Flowable-UI是什么 Flowable-UI是flowable自带的一套供开发人员体验的系统&#xff0c;它通过后台的UI建模&#xff0c;让开发人员了解Flowable的工作流程&#xff0c;同时它部署简单&#xff0c;只需要将对应的w…

医学AI最新研究·哈佛医学院·告别切片局限:3D病理如何革新癌症预后

小罗碎碎念 本期文章分享的主要是AI与肿瘤的复发、转移相关的最新研究。 筛选规则如下&#xff1a; (artificial intelligence or deep Learning or convolutional networks or transformer or selfattention or machine learning) and (Tumor metastasis or Recurrence of Ca…

Windows系统安装OpenSSH使用VScode远程连接内网Linux服务器开发

文章目录 &#x1f4a1;推荐 前言1、安装OpenSSH2、VS Code配置ssh3. 局域网测试连接远程服务器4. 公网远程连接4.1 ubuntu安装cpolar内网穿透4.2 创建隧道映射4.3 测试公网远程连接 5. 配置固定TCP端口地址5.1 保留一个固定TCP端口地址5.2 配置固定TCP端口地址5.3 测试固定公网…

视频批量裁剪助手:一键式高效缩小视频尺寸,极速提升工作效率的必备神器!

视频已经成为我们日常生活和工作中不可或缺的一部分。无论是个人vlog、企业宣传片&#xff0c;还是教学视频、广告素材&#xff0c;视频都承载着大量的信息和情感。然而&#xff0c;很多时候&#xff0c;我们手中的视频尺寸并不符合我们的需求&#xff0c;这时&#xff0c;一款…

Xilinx(AMD) FPGA通过ICAP原语读取芯片IDCODE实现方法

1 概述 Xilinx每种型号的FPGA芯片都有一个唯一的IDCODE与之对应&#xff0c;同一型号不同封装的IDCODE是相同的。IDCODE的获取方法包括JTAG、ICAP原语、AXI_HWICAP IP核等。获取IDCODE常用于根据芯片型号改变代码的功能&#xff0c;或者对代码进行授权保护&#xff0c;只能在指…

ROS | 用C++和python实现运动控制功能

基础知识&#xff1a; 用C实现&#xff1a; C代码&#xff1a; 用python实现&#xff1a; Python代码&#xff1a;

【编译原理复习笔记】语法分析-补充(二义性与LR错误处理)

二义性文法的 LR 分析 每个二义性文法都不是 LR 的 但是某些二义性文法更加简短&#xff0c;描述更方便 如 I7 和 I8 具有移进归约冲突 使用优先级和结合性解决冲突 对于 I7&#xff0c;由于乘号优先级高于加号&#xff0c;所以当下一个输入符号为乘号时&#xff0c;我们优…

Python 机器学习 基础 之 数据表示与特征工程 【单变量非线性变换 / 自动化特征选择/利用专家知识】的简单说明

Python 机器学习 基础 之 数据表示与特征工程 【单变量非线性变换 / 自动化特征选择/利用专家知识】的简单说明 目录 Python 机器学习 基础 之 数据表示与特征工程 【单变量非线性变换 / 自动化特征选择/利用专家知识】的简单说明 一、简单介绍 二、单变量非线性变换 三、自…

设计模式11——代理模式

写文章的初心主要是用来帮助自己快速的回忆这个模式该怎么用&#xff0c;主要是下面的UML图可以起到大作用&#xff0c;在你学习过一遍以后可能会遗忘&#xff0c;忘记了不要紧&#xff0c;只要看一眼UML图就能想起来了。同时也请大家多多指教。 代理模式&#xff08;Proxy&am…