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

Alles rund um die Programmierung mit Qt
Antworten
Willi2793
Beiträge: 147
Registriert: 29. September 2008 10:59
Kontaktdaten:

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

Beitrag 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
Zuletzt geändert von Willi2793 am 3. April 2009 18:03, insgesamt 2-mal geändert.
franzf
Beiträge: 3114
Registriert: 31. Mai 2006 11:15

Beitrag 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...
Willi2793
Beiträge: 147
Registriert: 29. September 2008 10:59
Kontaktdaten:

Beitrag 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.
pfid
Beiträge: 535
Registriert: 22. Februar 2008 16:59

Beitrag 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?
Willi2793
Beiträge: 147
Registriert: 29. September 2008 10:59
Kontaktdaten:

Beitrag 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:
franzf
Beiträge: 3114
Registriert: 31. Mai 2006 11:15

Beitrag 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
Willi2793
Beiträge: 147
Registriert: 29. September 2008 10:59
Kontaktdaten:

Beitrag 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?
franzf
Beiträge: 3114
Registriert: 31. Mai 2006 11:15

Beitrag 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. ;)
Willi2793
Beiträge: 147
Registriert: 29. September 2008 10:59
Kontaktdaten:

Beitrag 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!
Antworten