MySQL Datenbank unter C++ verwenden
In diesem Artikel zeige ich wie man eine MySQL Datenbank unter C++ verwenden kann. Über die Dokumentation auf der offiziellen MySQL Webseite ist das zwar auch zu erfahren, trotzdem habe ich für eine einfache Verbindung zu meiner Datenbank über 2 Stunden gebraucht… Alles was man falsch machen kann und wie es dann doch einfach möglich ist.
MySQL Datenbank unter C++ verwenden
In der Webentwicklung ist die MySQL Datenbank fast ein Standard, da sie integraler Bestandteil jedes LAMP Servers sind. Es gibt zwar mit MariaDB und PostgreSQL Alternativen, dieser werden aber relativ selten benutzt. Ich denke im Umfeld von der C++ Programmierung ist es umgekehrt (bitte korrigiert mich durch eure Erfahrungen). Dort ist es eher üblich sich mit großen DB Systemen wie Microsoft SQL Server oder Oracle DB zu verbinden. Trotzdem wollte ich herausfinden ob es einfach ist, eine MySQL Datenbank ins aktuelle C++ Projekt einzubinden.
mysqlcppconn
Basis der Implementierung ist der von MySQL angebotene Connector. Dieser hat mir leider große Schwierigkeiten gemacht und mir Stunden gekostet. Auf der Downloadseite steht ein nicht zu übersehender Hinweistext:
Aus dem Grund habe ich mir auch die aktuellste Version geladen. In meinem Fall war das ein Problem, um den folgenden Code zu verwenden sollte man sich die ältere Version 1.11.1 laden.
Der Download umfasst einen lib Ordner mit den dynamischen und statischen Bibliotheksdateien für das entsprechende System (bei mir Linux) und ein include Ordner mit den Headern. Beide müssen in den Settings vom Projekt eingebunden werden. Mein Testprogramm für den Verbindungstest unterscheidet sich nur minimal von jenem der Dokumentation:
#include <iostream> #include <mysql_connection.h> #include <cppconn/driver.h> #include <cppconn/exception.h> #include <cppconn/resultset.h> #include <cppconn/statement.h> using namespace std; int main(int argc, char **argv) { try{ sql::Driver *driver; sql::Connection *con; sql::Statement *stmt; sql::ResultSet *res; driver = get_driver_instance(); con = driver->connect("tcp://DOMAIN:3306", "DBUSER", "PASSWORD"); con->setSchema("DBNAME"); stmt = con->createStatement(); res = stmt->executeQuery("SELECT * FROM country"); // replace with your statement while (res->next()) { cout << "Land: "; cout << res->getString(2) << " ("; cout << res->getString(3) << ")" << endl; } delete res; delete stmt; delete con; } catch(sql::SQLException &err) { cout << "ERROR: " << err.what() << endl; } return 0; }
Wobei man bei dem Verbindungsaufbau korrekte Daten angeben muss. Dafür müsst ihr DOMAIN, DBUSER, PASSWORD und DBNAME mit euren Daten ersetzen. Das Programm setzt ein einfaches SELECT auf der Datenbank ab und gibt vom Ergebnis die 2. und 3. Spalte Zeilenweise aus. In meinem Fall sind das Ländernamen und das zugehörige Kürzel.
Beim Test ist mir sofort die große Wertezeit von 3-4 Sekunden aufgefallen bis das Ergebnis angezeigt wird. Das liegt an dem Request über das Internet und der für solche Abfragen nicht optimierter Datenbank und Server. Im lokalen Netzwerk sollte das Ergebnis unmittelbar da sein, ansonsten fehlt auf der Tabelle ein Index.
Problem mit aktuellster Version
Die aktuelle 8er Version erlaubt den Zugriff auf die Datenbank nur über die API. Diese kommuniziert aber nicht über den Standardport 3306. Das könnte bei selbst gehosteten bzw. lokal installierten Datenbanken eine gute Wahl sein, nicht jedoch bei einem Hostingpaket. Über den angegebenen Source Code für einen einfachen Verbindungsaufbau habe ich immer folgende Fehlermeldungen bekommen:
CDK Error: unexpected message
CDK Error: Connection refused (generic:111)
abhängig davon ob die angegebenen Verbindungsdaten mit oder ohne Port angegeben wurden. In jedem Fall endete das Testprogramm schon nach der Zeile des Verbindungsaufbaus. Ich gehe davon aus, dass der nötige Port von der Firewall beim Hoster geblockt wird. Das Problem wird man bei einer selbst gehosteten beziehungsweise lokalen Installation von MySQL vermutlich nicht haben.
Fazit
Eine MySQL Datenbank unter C++ verwenden ist einfach, den korrekten Connector vorausgesetzt. Bei Verbindungsfehlern ist entweder ein Tippfehler oder die Firewall am DB Server Schuld. In Ausnahmefehlern schafft man trotz korrektem Code keine Verbindung. In meinem Fall war es eine nicht über den MySQL Standardport versuchte Kommunikation, die vom Hoster unterbunden wird.
Welche Erfahrungen habt ihr mit MySQL unter C++?
Hi , ich habe ein Problem,
ich bekomme eine Fehlermeldung, dass in der COnfig.h in cppcon-Ordner mein Datentyp falsch ist. Haben sie eine Lösung dazu.
Benutzt wird mysql connector 1.11.11 und Boost 1.68.
Weißt du eventuell weiter?
Bitte um den genauen Fehler. Auf welchem System arbeitest du? Ich habe den mysqlconnector mittlerweile auch unter Windows in Verwendung. Dort hatte ich soweit ich weiß ein Problem bei der Verwendung bei der Kompilierung einer 64bit EXE und musste da was in den Visual Studio Settings ändern. Die config.h enthält ja zahlreiche WIN32 Abfragen…
Ich arbeite mit Windows 10 und Eclipse. Den Fehler mit der Config.h datei konnte ich beheben.
Jetzt stoße ich auf das nächste Problem:
..\src\test.cpp:23:32: error: call of overloaded ‚get_driver_instance()‘ is ambiguous
driver = get_driver_instance();
Alles ist soweit drinnen, die Libs sind gelinkt, die Header dateien, wenn diese benötigt waren includiert.
Auffällig ist, das der selbe Fehler auch mit VS2013 erscheind.
Bei MYSQL in den Server einstellungen steht:
„compiled for: (LINUX x86_64)“
könnte das einfach das Problem sein?
Ich habe es jeweilt mit dem 1.1.11 und 8.0.13 Connector versucht immer wieder derselbe Fehler.
My SQL ist privat bzw. nicht lokal.
Danke für die Antwort!
hey, also „‘get_driver_instance()’ is ambiguous“ deutet darauf hin, dass diese Methode nie korrekt aufgerufen werden kann. Solche Fehler treten auf, wenn über Header zwei Funktionen eingebunden werden die exakt gleich heißen, dann muss man diese voll qualifiziert angeben….zum Beispiel sdl::vector, falls man vector von einer anderen Header einbindet und der Compiler dann nicht weiß welche er nehmen soll. In deinem Fall fehlen mir die nötigen Infos, kann es sein, dass du beide Header, also für 1.1.11 und 8.0.13 eingebunden hast und der Kompiler schlicht nicht entscheiden kann von wo er die Funktion aufrufen soll?
Hi,
i randomly get this error CDK Error: Connection refused (generic:111). The application is able to connect to db for the first time but then if i kill the process i get CDK Error: Connection refused (generic:111). Any idea what’s causing it and how can i fix this on linux docker containers. My application and DB are hosted on separate docker containers running with privileged mode.