Seite 1 von 1

[gelöst] immer wieder QSqlDatabase::removeDatabase()

Verfasst: 1. April 2009 14:07
von Willi2793
Hallo,

ich weiß das dieses Thema schon öfter hier behandelt wurde. Und ich habe auch einige beiträge dazu gelesen und Ratschläge befolgt. Aber ich stehe entweder so sehr auf dem Schlauch das da gar nix mehr durchkommt oder ich sehe den Wald vor lauter Bäumen nicht.

Ich habe folgende Konsolen-Application:

main.cpp

Code: Alles auswählen

#include <QtCore/QCoreApplication>
#include "dbaccess.h"
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    DBAccess db;
    db.open();
    db.getData();

    return 0;
}
dbaccess.h

Code: Alles auswählen

#ifndef DBACCESS_H
#define DBACCESS_H

class DBAccess
{
public:
    DBAccess();
    virtual ~DBAccess();
    bool open();
    void getData();
};

#endif // DBACCESS_H
dbaccess.cpp

Code: Alles auswählen

#include <QDebug>
#include <QSqlDatabase>
#include <QSqlError>
#include <QSqlQuery>
#include <QVariant>
#include "dbaccess.h"

DBAccess::DBAccess()
{
    QSqlDatabase db = QSqlDatabase::addDatabase("QODBC");
    db.setDatabaseName("DRIVER=MySQL ODBC 3.51 Driver;DATABASE=database");
    db.setHostName("127.0.0.1");
    db.setUserName("user");
    db.setPassword("password");
}

DBAccess::~DBAccess() {
    if (QSqlDatabase::database().isOpen()) {
        QSqlDatabase::database().close();
    }
    QSqlDatabase::removeDatabase(QSqlDatabase::database().connectionName());
}

bool DBAccess::open() {
    return QSqlDatabase::database().open();
}

void DBAccess::getData() {
    if (QSqlDatabase::database().isOpen()) {
        QSqlQuery qu;
        qu.exec("SELECT feld1, feld2 FROM tabelle ORDER BY feld1");
        while(qu.next()) {
            QString mc = qu.value(0).toString();
            QString mn = qu.value(1).toString();
            qDebug() << "Feld1: " << mc << "   Feld2: " << mn;
        }
        qu.clear();
    } else {
        QSqlError err = QSqlDatabase::database().lastError();
        qDebug() << "DatabaseText: " << err.databaseText();
        qDebug() << "DriverText:   " << err.driverText();
        qDebug() << "Number:       " << err.number();
    }
}
Die datenbank-Abfrage funktioniert wunderbar. Also Initialisierung, Open usw scheint okay zu sein. Aber am Ende bekomme ich den "beliebten" Fehler:

Code: Alles auswählen

QSqlDatabasePrivate::removeDatabase: connection 'qt_sql_default_connection' is still in use, all queries will cease to work.
Ich bilde mir aber ein das ich alle Verbindungen abgebaut bzw. korrekt beendet habe und alle Instanzen auch keine Gültigkeit mehr haben. Aber warum erscheint diese Meldung immer noch?

Grüße,
Willi

Verfasst: 1. April 2009 14:25
von franzf
QString QSqlDatabase::databaseName () const

Returns the connection's database name, which may be empty. Note: The database name is not the connection name.
Somit bringt dein remove absolut rein gar nix ;)

Du hast die QSqlDatabse::connectionNames(). Hast du nur eine DB, sollte ein

Code: Alles auswählen

QSqlDatabase::removeDatabase( QSqlDatabase::connectionNames().at(0) );
das tun was du willst.

// edit:
sry, hab mich bei deinem Code verlesen, du verwendest ja im Destruktor connectionName() und nicht databaseName().
Trotzdem steht auch da Hinweis in der Doku:
Returns the connection name, which may be empty.
Also per qDebug() mal den connectionName() ausgeben lassen...

Verfasst: 1. April 2009 14:36
von Willi2793
Vielen Dank für den rat. Hat aber leider Nichts gebracht. Ich habe den Destruktor jetzt mit dem qDebug() erweitert und er sieht jetzt so aus:

Code: Alles auswählen

DBAccess::~DBAccess() {
    if (QSqlDatabase::database().isOpen()) {
        QSqlDatabase::database().close();
    }
    qDebug() << QSqlDatabase::database().connectionName();
    QSqlDatabase::removeDatabase(QSqlDatabase::database().connectionName());
}
und bringt folgende Ausgabe:

Code: Alles auswählen

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

Verfasst: 1. April 2009 15:21
von pfid
Und die DB, die du so:

Code: Alles auswählen

    if (QSqlDatabase::database().isOpen()) {
        QSqlDatabase::database().close(); 
zumachen willst, ist auch offen, und ist auch die die du aufgemacht hast, ja?

Verfasst: 1. April 2009 15:30
von Willi2793
Würde ich jedenfalls so sehen. den kompletten Source-Code des gesamten Projektes (angelegt um das zu testen) siehst Du im ersten Post. Nur die sensiblen daten geändert :wink:

Verfasst: 1. April 2009 15:56
von franzf
Ok, entmystifiziert ;)
QSqlDatabase::database() erhöht den internen referenz-Zähler auf das jewilige DB-Objekt (in deinem Fall die default-Database). Beim Zerstören wird der Zähler runtergezählt. (Läuft per QAtomicInt)
Falls die Anzahl der Referenzen größer 0 ist, spuckt QSqlDatabasePrivate diese Meldung aus.

Wenn du jetzt diese Zeile nimmst:

Code: Alles auswählen

QSqlDatabase::removeDatabase(QSqlDatabase::database().connectionName()); 
Referenzierst du ja für dein removeDatabase noch einmal das Objekt. Klar, deshalb kommt die Meldung.
So kommt se nimmer ;)

Code: Alles auswählen

QString cn = QSqlDatabase::database().connectionName();
QSqlDatabase::removeDatabase(cn);
// Nachtrag:
definier dir doch nen Kürzel für das QSqlDatabase::database(). Ist ja grausam, das immer so tippen zu müssen. Einfach im Header so ein

Code: Alles auswählen

#define DB QSqlDatabase::database()
:P

Verfasst: 1. April 2009 16:07
von Willi2793
Super! Vielen Dank. Jetzt funktioniert es wie ich es mir vorstelle.

Wie soll man als QT-Neuling da drauf kommen? :)

Ich denke der remove ist auch saubere programmierung, oder?

Verfasst: 1. April 2009 17:43
von franzf
Willi2793 hat geschrieben:Ich denke der remove ist auch saubere programmierung, oder?
Naja, ist wohl wurscht...
Die db-Objekte sollten alle selber zerstört werden, das removeDatabase() erledigt das ja wie erwähnt nicht automatisch für dich.
Und der globale QHash wird mit Programmende auch über den Jordan geschickt.

Von dem her ist das removeDatabase() nicht wirklich notwendig. ;)

Verfasst: 1. April 2009 18:03
von Willi2793
Ich verstehe. Aber ich bin da von der alten Schule und räume meine Ressourcen gerne hinter mir auf.

Vielen Dank jedenfalls. Du hast mir sehr geholfen!