首页 > 解决方案 > qt批量插入sqlite

问题描述

对于 qt/qml 项目,我正在向数据库中插入。因为要发送大量数据(200+ 次插入/秒),所以我想批量发送。插入到不同的表中。我已经准备好了查询。我做了一种方法,应该在达到 100 个查询后提交查询。

//in the constructor i laready say mdb.transaction() for the first run.
bool DatabaseWriter::executeQuery(QString insertQuery)
{
   queryCounter ++;
   qDebug() << QString::number(queryCounter);
   QSqlQuery query(mydb);

    if(!query.exec(insertQuery))
    {
        qDebug("%s.", qPrintable(mydb.lastError().text()));
        qDebug() << "Something went wrong while running " + insertQuery + " from the database";
        return false;
    }
    if(queryCounter > 100)
    {
         qDebug() <<  "Should commit";
        if(!mydb.commit())
        {
            qDebug() <<  "commit failed";
        }
        mydb.transaction();
        queryCounter = 0;
    }

    return true;
}

但是 mydb.commit() 返回 false。进行批量插入的正确方法是什么?

我也试过:

if(query != ""){

    query_to_commit += query +";";
    insert_counter ++;
    if(insert_counter > 100)
    {
         dbWriter.executeQuery("BEGIN TRANSACTION; "+query_to_commit+ " COMMIT;");
         insert_counter = 0;
         query_to_commit = "";
         CustomLogger::log("Running bulk insert");
    }
}

这会生成一个批量事务,该事务在我的 sqlite 数据库中执行时可以正常工作,但在我使用代码执行时却不行,在我的代码中我得到:Driver not loaded Driver not loaded.运行单个插入查询时我没有收到此错误。

为了简单起见,我该如何运行,例如:

INSERT  INTO settings (name, x, y) VALUES('somename', 100, 20)
INSERT  INTO different_table(bla, x, y) VALUES('bla', 100, 20)

一口气而不是两次做。或者我该如何执行:

BEGIN TRANSACTION;
INSERT  INTO settings (name, x, y) VALUES('somename', 100, 20)
INSERT  INTO different_table(bla, x, y) VALUES('bla', 100, 20)
COMMIT;

主要目标是不要每秒写 200 次,而是一次完成,如果我每秒写 200 次,我的 gui 会被阻塞/错误(我猜是在同一个线程上)。

标签: sqliteqt

解决方案


我做了一个单独的查询thead,我的头文件:

#ifndef QUERYTHREAD_H
#define QUERYTHREAD_H
#include <QThreadPool>
#include <QString>
#include <QSqlQuery>
#include <QSqlDatabase>

class QueryThread : public QRunnable
{
    QString query_to_run;
    static int queryNumber;

public:
    QueryThread(QString query_list);
    void run();
};


#endif // QUERYTHREAD_H

我的 cpp 文件:

#include "querythread.h"
#include <QDebug>
#include <windows.h> // for Sleep
#include <QSqlError>
#include "customlogger.h"
#include "databasewriter.h"

int QueryThread::queryNumber = 1;

QueryThread::QueryThread(QString query)
{
    this->query_to_run = query;
}

void QueryThread::run()
{

    {
        // Make sure to have a unique database connection name by using the a static counter.
        QString connectionName = "connection_name_"+QString::number(queryNumber ++);
        QSqlDatabase mydb = QSqlDatabase::addDatabase("QSQLITE", connectionName);
        mydb.setDatabaseName(DatabaseWriter::dirPath);

        if(!mydb.open()){
            CustomLogger::log("Cant open DB");
            return;
        }
        QSqlQuery query(mydb);
        if(!query.exec(query_to_run))
        {
            CustomLogger::log(qPrintable(mydb.lastError().text()));
            CustomLogger::log("Something went wrong while running query: " + query_to_run);
        }
        mydb.close();
    }
    QSqlDatabase::removeDatabase("QSQLITE");
}

我开始一个新的查询:

QueryThread *queryThread = new QueryThread(insertQuery);
// QThreadPool takes ownership and deletes 'queryThread' automatically
QThreadPool::globalInstance()->start(queryThread);

此实现在 ui 线程的单独线程上运行查询。它为每个插入打开一个连接,所以我不确定这个解决方案是否不会导致性能问题。到目前为止,在 16 小时内插入 1.600.000 次看起来还不错。

如果您进行大量插入操作,则可以将数据库置于wal 模式以避免数据库被锁定。


推荐阅读