Unsolved Richtiger Umgang mit QSqlDatabase
-
So, ich habe mein Code so umgeschrieben das die Verbindung erst mal gar nicht geschlossen wird.
Auch wird erst mal keine Verbindung zur QSQLite hergestellt sondern nur zur QMYSQL.Im Code selbst kommt dann, wenn ich eine Funktion die die MySQL aufbaut die Warnmeldung
QSqlDatabasePrivate::addDatabase: duplicate connection name 'qt_sql_default_connection', old connection removed.
Meine Header habe ich mit #ifndef und #ifdef deklariert, also diese wird nur einmal durchlaufen.
Ich versteht noch nicht, wie diese Fehlermeldung zustande kommt.Kann es sein das man diese Fehlermeldung bekommt wenn man das Passwort, Datenbank usw. setzt. Darf diese Aktion auch nur einmal vorkommen? bzw. erst wieder wenn man die Datenbank geschlossen hat?
Denn das wird bei mir jedes mal mit den Konstruktor gemacht ohne das ich Prüfe ob die Datenbank offen ist oder nicht.Gruß Knasan
-
@knasan
"duplicate connection name 'qt_sql_default_connection', old connection removed" - es wurde wohl schon eine default connection vorher aufgebaut. Wo weis ich nicht, da ich ja den Code nicht habe."Im Code selbst kommt dann, wenn ich eine Funktion die die MySQL aufbaut die Warnmeldung" - wo wird diese aufgerufen?
-
Guten Morgen,
in meiner Header
QSqlDatabase dbCentassist = QSqlDatabase::addDatabase("QMYSQL");
in meiner CPP Klasse von meiner Datenbank im Kunstruktor
QCSql::QCSql() { qDebug() << "QCSql:QCSql()"; qDebug() << "QCSql::QCSql() - Connect to DB"; // Develop dbCentassist.setUserName("user"); dbCentassist.setPassword("geheim"); if(isDevelop) { qDebug() << "QCSql::QCSql() - Develop"; dbCentassist.setHostName("hostname"); dbCentassist.setDatabaseName("Datenbank"); } else { // WORK qDebug() << "QCSql::QCSql() - Work"; dbCentassist.setHostName("hostname2"); dbCentassist.setDatabaseName("Datenbank"); } }
In meiner Hauptklasse mache ich dann ein
QCSql qcsql; QCsql.mysqlquery("INSERT INTO ....");
Das mach ich halt in Slots und Funktionen in meiner Hauptklasse wo ich diese brauche.
Gruß Knasan
-
Da ich jetzt nicht wusste ob diese Informationen genügen, habe ich eine Example geschrieben wie ich es in meinem Original Code gemacht habe. Evtl. kann mir jemand sagen was ich falsch mache.
main.cpp
#include "forum.h" #include <QApplication> int main(int argc, char *argv[]) { QApplication a(argc, argv); Forum w; w.show(); return a.exec(); }
forum.cpp
#include "forum.h" #include "ui_forum.h" #include "mysqlconnect.h" #include <QDebug> #include <QStringList> #include <QPlainTextEdit> Forum::Forum(QWidget *parent) : QMainWindow(parent), ui(new Ui::Forum) { ui->setupUi(this); connect(ui->pushButton, SIGNAL(clicked()), this, SLOT(GetUserInfo())); } Forum::~Forum() { delete ui; } void Forum::GetUserInfo() { // User Information setzen MySqlConnect sqlc; QStringList list = sqlc.GetUserInfo("SELECT * FROM person WHERE name = 'exampleuser'"); qDebug() << list.toVector(); QString PlainText; foreach(const QString &str, list) { qDebug() << str; PlainText += " " + str; } ui->plainTextEdit->insertPlainText(PlainText); }
mysqlconnect.cpp
#include "mysqlconnect.h" #include <QSqlDatabase> #include <QDebug> #include <QSqlQuery> #include <QStringList> #include <QSqlError> MySqlConnect::MySqlConnect(QObject *parent) : QObject(parent) { sqldb.setHostName("localhost"); sqldb.setPassword("1b7cq"); sqldb.setUserName("forum"); sqldb.setDatabaseName("forumsqldatabase"); } QStringList MySqlConnect::GetUserInfo(const QString &mysqlStr) { qDebug() << "GetUserInfo: " << mysqlStr; if(!sqldb.isOpen()) { sqldb.open(); } QStringList resultList; QSqlQuery query = MyQuery(mysqlStr); qDebug() << query.value(0); while(query.next()) { resultList.append(query.value(0).toString()); resultList.append(query.value(1).toString()); resultList.append(query.value(2).toString()); } qDebug() << "resultList: " << resultList.toVector(); return resultList; } QSqlQuery MySqlConnect::MyQuery(const QString &myQuery) { qDebug() << "MyQuery: " << myQuery; QSqlQuery query(myQuery); qDebug() << query.lastError(); return query; }
forum.h
#ifndef FORUM_H #define FORUM_H #include <QMainWindow> namespace Ui { class Forum; } class Forum : public QMainWindow { Q_OBJECT public: explicit Forum(QWidget *parent = 0); ~Forum(); private: Ui::Forum *ui; private slots: void GetUserInfo(); }; #endif // FORUM_H
mysqlconnect.h
#ifndef MYSQLCONNECT_H #define MYSQLCONNECT_H #include <QObject> #include <QSqlDatabase> #include <QStringList> class MySqlConnect : public QObject { Q_OBJECT public: explicit MySqlConnect(QObject *parent = 0); QSqlQuery MyQuery(const QString &myQuery); QStringList GetUserInfo(const QString &mysqlStr); private: QSqlDatabase sqldb = QSqlDatabase::addDatabase("QMYSQL"); }; #endif // MYSQLCONNECT_H
in der UI habe ich lediglich einen Button und ein PlainText hinzugefügt.
Beim drücken des Buttons wird der Result in den PlainTextEdit eingefügt.Auch hier bekomme ich wieder die Fehlermeldung (beim zweiten drücken des Buttons)
QSqlDatabasePrivate::addDatabase: duplicate connection name 'qt_sql_default_connection', old connection removed.
Wo müsste man jetzt ein removeDatabase einfügen ohne die Verbindung zur Datenbank beendet wird. Oder Vewende ich QSQLDatabase falsch?
Ich danke euch schon mal im Vorraus für eure hilfe.
Gruß Knasan
-
@knasan said in Richtiger Umgang mit QSqlDatabase:
Wo müsste man jetzt ein removeDatabase einfügen
Nirgendwo. Man muss dafür sorgen, Dass die Datenbank nur einmal benutzt wird.
Das Problem ist hier:oid Forum::GetUserInfo() { // User Information setzen MySqlConnect sqlc; ...
Bei jedem Aufruf von Forum::GetUserInfo() wird eine Instanz von MySqlConnect erzeugt, die wiederum die DB-Verbindung aufbaut was zu dieser Warnung führt:
QSqlDatabase sqldb = QSqlDatabase::addDatabase("QMYSQL");
Solche Classen werden üblicherweise als Singleton benutzt um zu verhindern, dass mehr als eine Instanz erzeugt wird. Allerdings sind Singletons problematisch. Es ist besser innerhalb von MySqlConnect sicher zu stellen, dass die Verbindung nur einmal aufgebaut wird. Dafür kann man zuerst http://doc.qt.io/qt-5/qsqldatabase.html#database mit dem DB-Namen aufrufen. Falls QSqlDatabase, welches zurück gegeben wird, invalid ist (http://doc.qt.io/qt-5/qsqldatabase.html#isValid) wurde die Verbindung noch nicht aufgebaut, sonst existiert diese schon. Alternativ deklariert man die sqldb Variable als static, dann wird diese nur einmal initialisiert.
Eigentlich is die sqlc Variable in MySqlConnect nicht notwendig, da ja QSqlDatabase diese ja schon vorhält. -
Morgen, Danke @jsulm für die Ausführliche Erklärung. Ich werde es mir heute Abend nach der Arbeit nochmal genauer ansehen. Was ich noch nicht ganz verstanden habe ist.
Alternativ deklariert man die sqldb Variable als static, dann wird diese nur einmal initialisiert.
Auf die schnelle wollte ich einfach mal Testen,
static QSqlDatabase sqldb = QSqlDatabase::addDatabase("QMYSQL");
Das nahm mein Kompiler aber erst gar nicht an.
Eigentlich is die sqlc Variable in MySqlConnect nicht notwendig, da ja QSqlDatabase diese ja schon vorhält.
Im Beispiel habe ich in MySqlConnect die Variable sqlc gar nicht verwendet, nur im Forum. Und dort Initialisiere ich sozusagen die Klasse damit ich auf deren Funktionen zugreifen kann. Ist das falsch?
Wenn ja, kann mir jemand ein Beispiel geben wie das richtig eingesetzt wird.
Danke!
Gruß knasan
-
// Im header static QSqlDatabase sqldb; //in cpp QSqlDatabase MySqlConnect::sqldb = QSqlDatabase::addDatabase("QMYSQL");
"Im Beispiel habe ich in MySqlConnect die Variable sqlc gar nicht verwendet" - spielt ja keine Rolle, da sqldb immer initialisiert wird unabhängig davon ob es benutzt wird oder nicht.
-
Also, so wirklich will das bei mir noch nicht.
Im Header habe ich QSqlDatabase als static deklariert.mysqlconnect.h
private: static QSqlDatabase sqldb;
In mysqlconnect.cpp
Habe ich ein addDatabase versucht.
QSqlDatabase MySqlConnect::sqldb = QSqlDatabase::addDatabase("QMYSQL");
Dann bekommich ich die Fehlermeldung:
qualified-id declaration before = token.und wenn einfach nur
QSqlDatabase sqldb = QSqlDatabase::addDatabase("QMYSQL");
Mache, was für mich auf den ersten Blick auch logisch erscheint, da ich ja die Variable sqldb deklariert habe, bekomme ich in jeder Funktion innerhalb von MySQLConnect die Fehlermeldung:
undefinied reference to MySqlConnect::sqldb
oder muss ich die Datenbank nicht in mysqlconnect.cpp machen sondern, wie in diesem Beispiel in Forum.cpp ?
Das verstehe ich noch nicht so ganz.
-
@knasan said in Richtiger Umgang mit QSqlDatabase:
Habe ich ein addDatabase versucht.
QSqlDatabase MySqlConnect::sqldb = QSqlDatabase::addDatabase("QMYSQL");Wo? Es muss in MySqlConnect.cpp passieren.
QSqlDatabase sqldb = QSqlDatabase::addDatabase("QMYSQL");
das definiert eine neue sqldb Variable die überhaupt nichts mit MySqlConnect zu tun hat.
"was für mich auf den ersten Blick auch logisch erscheint, da ich ja die Variable sqldb deklariert habe" - deklariert wurde diese als Member-Variable in MySqlConnect, in der Zeile oben wird aber eine neue Variable mit dem gleichen namen definiert. -
Ich habe es im constructor in mysqlconnect.cpp eingetragen und die oben genannten Fehlermeldung bekommen.
mysqlconnect.h
private: static QSqlDatabase sqldb;
mysqlconnect.cpp
MySqlConnect::MySqlConnect(QObject *parent) : QObject(parent) { QSqlDatabase MySqlConnect::sqldb = QSqlDatabase::addDatabase("QMYSQL"); sqldb.setHostName("localhost"); sqldb.setPassword("1b7cq"); sqldb.setUserName("forum"); sqldb.setDatabaseName("forumsqldatabase"); }
Dann erhalte ich die Fehlermeldung:
mysqlconnect.cpp:12: Fehler: qualified-id in declaration before ‘=’ token QSqlDatabase MySqlConnect::sqldb = QSqlDatabase::addDatabase("QMYSQL"); ^
Gruß Knasan
-
@knasan Das gehört NICHT in den Konstruktor! Statische variablen werden in C++ nur einmal initialisiert.
Siehe: https://www.tutorialspoint.com/cplusplus/cpp_static_members.htm -
Hallo @jsulm, danke für diesen Hinweis. Hab noch viel zu Lernen ;-)
Ich muss mir das Beispiel vom Link mal durchspielen und damit etwas rumspielen um das ganze komplett zu verstehen.
Ich habe jetzt eine neu Funktion OpenDBSQL(); hinzugefügt als privat. Aber auch hier erhalte ich die gleiche Fehlermeldung:
mysqlconnect.cpp:15: Fehler: qualified-id in declaration before ‘=’ token QSqlDatabase MySqlConnect::sqldb = QSqlDatabase::addDatabase("QMYSQL"); ^
Gruß Knasan
-
@knasan Noch mal: wenn sqldb static ist dann gehört diese Zeile in KEINE Methode/Konstruktor, sondern einfach in eine cpp Datei:
QSqlDatabase MySqlConnect::sqldb = QSqlDatabase::addDatabase("QMYSQL"); MySqlConnect::MySqlConnect(QObject *parent) : QObject(parent) { sqldb.setHostName("localhost"); sqldb.setPassword("1b7cq"); sqldb.setUserName("forum"); sqldb.setDatabaseName("forumsqldatabase"); }
Das stellt sicher, dass statische Variablen nur ein Mal initialisiert werden. Das wird auch in dem Link von mir so gemacht.
-
Sorry wenn ich jetzt nochmal genauer Nachfrage. Meinst du, dies gehört nicht in mysqlconnect.cpp sondern in einer Datei die meine Klasse mysqlconnect verwendet? In meinem Beispiel also in forum.cpp?
Gruß knasan
-
@knasan Doch, es gehört in mysqlconnect.cpp (wobei man das auch irgendwo anders unterbringen kann wenn man will), aber nicht in eine Methode, sondern so wie ich es oben gezeigt habe.
-
Achso, es muss außerhalb einer Funktion stehen. Sozusagen global deklariert werden aber in mysqlconnect.cpp und da das Schlüsselwort static verwendet wurde wird diese nur einmal initialisiert.
-
@knasan Genau
-
@jsulm vielen lieben Dank für diese Erklärung. Hab viel Dazugelernt.
Ich habe es in mein Hauptprojekt getestet und Funktioniert auch soweit super.
Leider gibt es immer ein "aber" und so auch in meinem Fall.In meinem Hauptprojekt verwende ich zwei Datenbanken, eine QMYSQL und eine QSQLITE.
Sobald ich die QSQLITE auch als Static deklariere, funktioniert der Zugriff auf MySQL gar nicht mehr - "Driver not loaded". Es spielt hierbei keine Rolle ob ich die Klasse überhaupt verwende oder nicht. SQLite Funktioniert weiterhin.Ich wollte dieses Problem mit eigen definierte ConnectionName umgehen. Dann habe ich jedoch überhaupt gar keinen Zugriff auf die Datenbank mehr. (MySQL und SQLite)
QSqlDatabase MySqlConnect:sqldb = QSqlDatabase::addDatabase("QMYSQL","first");
Verwende ich keine expliziten ConnectionName oder "qt_sql_default_connection", funktioniert der Zugriff
QSqlDatabase MySqlConnect:sqldb = QSqlDatabase::addDatabase("QMYSQL","qt_sql_default_connection");
Gruß Knasan
-
@knasan said in Richtiger Umgang mit QSqlDatabase:
Driver not loaded
Das ist ein komplett anderes Problem. Sehr wahrscheinlich fehlt die MySQL Client Library.
Siehe z.B. hier was zu tun ist: https://stackoverflow.com/questions/40130698/qt-5-7-mysql-driver-not-loaded -
@jsulm said in Richtiger Umgang mit QSqlDatabase:
Das ist ein komplett anderes Problem. Sehr wahrscheinlich fehlt die MySQL Client Library.
Siehe z.B. hier was zu tun ist: https://stackoverflow.com/questions/40130698/qt-5-7-mysql-driver-not-loadedDie Verbindung geht ja, wenn ich nur QMYSQL Verwende. Nur Zusammen mit einer weiteren Datenbank QSQLITE klappt die Verbindung nicht mehr. Die Treiber für MySQL unter Linux und den Connector C++ für Windows habe ich auf meine Systeme drauf. Daran kann es also nicht liegen.