QSqlDatabase: Как избежать использования qt_sql_default_connection и использовать дублирование предупреждений, связанных с подключением? - PullRequest
1 голос
/ 16 марта 2019

Извините, если это тривиальный вопрос, но я пытался создать небольшой .ui, который использовал QSQLITE в качестве базы данных и который использовал QTableView, чтобы показать 4 столбца в файле базы данных по умолчанию в качестве примера.

Я отлаживал проблему со всех сторон, изменял логические операции SQL и реструктурировал конструктор более простым способом, но ошибка все еще остается.

После окончания настройки всех параметров я получаю эту ошибку:

QSqlDatabasePrivate::removeDatabase: connection 'qt_sql_default_connection' is still in use, all queries will cease to work.

И

QSqlDatabasePrivate::addDatabase: duplicate connection name 'qt_sql_default_connection', old connection removed.

Я посмотрел несколько источников, описывающих эту ошибку, таких как этот источник , этот другой источник . Также это было полезно, но все равно ничего не происходит. Официальная документация предлагает «неправильный» и «правильный» способ сделать это здесь . но ошибка все еще остается. После всех этих различных вариантов я вернул код в более сжатую форму и надеюсь, что кто-то сможет пролить свет на эту проблему.

Ниже приведен код:

mainwindow.h

private:
    QString temporaryFolder;
    dataInfo *mNewDatabaseImages;
    QSqlTableModel *mNewTableImages;

mainwindow.cpp

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    temporaryFolder = "/home/to/Desktop/tempDBFolder/tmp.db";
    QFile dbRem(temporaryFolder);
    dbRem.remove();
    mNewDatabaseImages = new dataInfo(this);
    mNewDatabaseImages->initDataBase(temporaryFolder);
    mNewDatabaseImages->confDataBase();
    mNewTableImages = new QSqlTableModel(this, mNewDatabaseImages->getDatabase());
    mNewTableImages->setTable("leftCamTable");
    mNewTableImages->select();
    ui->bookMarkTableView->setModel(mNewTableImages);
    ui->bookMarkTableView->showColumn(true);
}

datainfo.h

#ifndef DATAINFO_H
#define DATAINFO_H
#include <QObject>
#include <QSqlDatabase>
#include "imageparam.h"

class dataInfo : public QObject
{
    Q_OBJECT
public:
    explicit dataInfo(QObject *parent = nullptr);
    bool initDataBase(const QString &nameDB);
    bool confDataBase();
    bool addItem(ImageParam* imageItem);
    QSqlDatabase getDatabase();
private:
    QString mError;
    QSqlDatabase mDBImages;
};
#endif // DATAINFO_H

datainfo.cpp

#include "datainfo.h"
#include <QSqlQuery>
#include <QSqlError>
#include <QDebug>
#include <QVariant>
#include <QMessageBox>

#define CREATE_TABLE \
    " CREATE TABLE IF NOT EXISTS imageTable" \
    " (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL" \
    " path1 TEXT NOT NULL" \
    " path2 TEXT NOT NULL" \
    " imageA BLOB NOT NULL" \
    " imageB BLOB NOT NULL)"

dataInfo::dataInfo(QObject *parent) : QObject(parent)
{}

bool dataInfo::initDataBase(const QString &nameDB)
{
    mDBImages = QSqlDatabase::addDatabase("QSQLITE");
    mDBImages.setDatabaseName(nameDB);
    bool ok = mDBImages.open();
    if(!ok) {
        mError = mDBImages.lastError().text();
        qDebug() << mError;
    }
    return ok;
}

bool dataInfo::confDataBase()
{
    QSqlQuery qry;
    bool ok = qry.exec(CREATE_TABLE);
    if(!ok) {
        mError = qry.lastError().text();
    }
    return ok;
}

bool dataInfo::addItem(ImageParam *imageItem)
{
    QSqlQuery qry;
    qry.prepare("INSERT INTO imageTable (path1, path2, imageA, imageB)" \
                " VALUES (?,?,?,?)");
    qry.addBindValue(imageItem->path1());
    qry.addBindValue(imageItem->path2());
    qry.addBindValue(imageItem->image1());
    qry.addBindValue(imageItem->image2());
    bool ok = qry.exec();
    if(!ok) {
        mError = qry.lastError().text();
    }
    return ok;
}

QSqlDatabase dataInfo::getDatabase()
{
    return mDBImages;
}

Я также посмотрел на этот пост , в котором предлагалось сначала установить имя для базы данных, но я уже делаю это в функции initDataBase(const QString &nameDB). Здесь post , который предложил процедуру, которая ниже:

db->setDatabaseName("name");
if(!db->open()) {
    qDebug() << "Error opening ";
    return false;
}

Просьба пролить свет на возможное решение.

1 Ответ

3 голосов
/ 16 марта 2019

Краткий ответ

  • Вы должны указать базу данных, на которой вы хотите запустить QSqlQuery, иначе они будут работать в базе данных по умолчанию. Вы можете указать базу данных в конструкторе QSqlQuery с помощью

    QSqlQuery query(QSqlDatabase::database("my-db"));

  • Вы храните копию QSqlDatabase в качестве члена вашего dataInfo класса, что не позволит ему правильно закрыться. Вместо этого просто используйте статический QSqlDatabase::database("name") при необходимости.

    auto db = QSqlDatabase::database("my-db");

Подробнее

Предоставление правильной базы данных для QSqlQuery

Измените все ваши использования QSqlQuery. Например для confDataBase:

bool dataInfo::confDataBase()
{
    // Explicitly provide your database to the query
    // Otherwise the default database is used
    QSqlQuery qry(getDatabase());
    bool ok = qry.exec(CREATE_TABLE);
    if(!ok) {
        mError = qry.lastError().text();
    }
    return ok;
}

Не сохраняются атрибуты QSqlDatabase

Из документации:

Предупреждение : Настоятельно не рекомендуется хранить копию QSqlDatabase как член класса, так как это предотвратит правильную очистку экземпляра при завершении работы. Если вам нужен доступ к существующей базе данных QSqlDatabase, доступ к ней должен осуществляться с помощью database (). Если вы решили использовать переменную-член QSqlDatabase, ее необходимо удалить до удаления экземпляра QCoreApplication, в противном случае это может привести к неопределенному поведению.

Вместо этого сохраните имя вашей базы данных в своем классе и измените getDatabase на

dataInfo.cpp

bool dataInfo::initDataBase(const QString &nameDB)
{
    // Save database's name
    mDBName = nameDB;
    // Use the database locally, without storing it
    auto dbImages = QSqlDatabase::addDatabase("QSQLITE", nameDB);
    bool ok = dbImages.open();
    if(!ok) {
        mError = dbImages.lastError().text();
        qDebug() << mError;
    }
    return ok;
}

QSqlDatabase dataInfo::getDatabase()
{
    return QSqlDatabase::database(mDBName);
}

dataInfo.h

private:
    QString mError;
    QString mDBName;

Код Qt, генерирующий предупреждение

Чтобы посмотреть на реальный код, выдающий ошибку: https://code.woboq.org/qt5/qtbase/src/sql/kernel/qsqldatabase.cpp.html#170

invalidateDb используется при добавлении или удалении соединений и вызовет ошибку, если счетчик ссылок> 1. Если вы удерживаете один из них, это вызовет ошибку.

...