Qt - tworzenie połączenia z bazą danych i wysyłanie zapytań SQL do serwera
Stronę tą wyświetlono już: 4284 razy
Wstęp
Do tworzenia połączenia z bazą danych SQL w Qt służy klasa QSqlDatabase. Niestety połączenie z bazą danych uruchomioną na lokalnym serwerze lub gdzieś na serwerze, do którego dostęp jest umożliwiony poprzez sieć lokalną czy też globalną wymaga odpowiedniego sterownika. W przypadku MySQL sterownik ten nie jest domyślnie dostępny. Oznacza to, że aby możliwe było realizowanie połączenia z bazą danych MySQL trzeba ściągnąć z strony dev.mysql.com/downloads/connector/c/ odpowiednią paczkę ze sterownikami zwracając uwagę na wersję Qt Creator-a zainstalowaną na komputerze, gdyż dla wersji 32-bitowej jest inna paczka a dla 64-bitowej inna. W moim przypadku pobrałem wersję 32-bitową i ją rozpakowałem a następnie plik libmysql.dll znajdujący się w folderze lib rozpakowanych plików należy przekopiować do folderu kompilatora, który w moim przypadku znajduje się w:
- sciezka_do_folderu_z_Qt/Qt/Qt5.6.3/5.6.3/mingw49_32/bin
To jednak nie wszystko, albowiem zaprawdę powiadam wam, że konieczne jest jeszcze w pliku .pro dodanie ścieżki do plików nagłówkowych z rozpakowanej paczki:
- INCLUDEPATH += sciezka_do_folderu_z_paczką/mysql-connector-c-6.1.11-win32/include
Skoro już jestem w pliku .pro to dodaję jeszcze następującą linijkę:
- QT += sql
dzięki której będzie możliwy dostęp do plików nagłówkowych związanych z obsługą baz danych SQL.
Tworzenie w MySQL przykładową bazę danych do testów
Do testów konieczne jest utworzenie bazy danych oraz jakiegoś testowego użytkownika, który ma dostęp i pełne uprawnienia jedynie do tej bazy danych. Robię to w konsoli systemowej logując się w następujący sposób:
- mysql -u root -p
Parametr -u oznacza, że wprowadzam nazwę użytkownika, zaś -p, że chcę podać hasło. Po zalogowaniu tworzę bazę danych i użytkownika oraz jakąś prostą tabelkę z jednym rekordem za pomocą następującego kody SQL:
- CREATE DATABASE library CHARACTER SET utf8 COLLATE utf8_general_ci
- CREATE USER gienek@localhost IDENTIFIED BY 'password';
- GRANT ALL ON library.* TO gienek@localhost;
- USE library;
- CREATE TABLE books (
- id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
- title CHAR(255) NOT NULL,
- author CHAR(255) NOT NULL
- );
- INSERT INTO books (title, author)
- VALUES
- ('Rio Anaconda', 'Wojciech Cejrowski');
W pierwszej linijce powyższego kodu tworzę bazę danych o nazwie library, w której kodowanie znaków zostało ustawione na UTF-8. W trzeciej linijce kodu tworzę użytkownika o dźwięcznej i niewiele znaczącej nazwie gienek, który ma dostęp do bazy danych jedynie przez localhost. Gienek to sprytny gość, więc do logowania używa niewymagającego zapamiętywania hasła o nazwie password. W piątej linijce gienkowi przydzielany jest przywilej korzystania z bazy danych library na wszystkie w niej znajdujące się tabele z możliwością wykonywania wszystkich dostępnych operacji. W siódmej linijce wchodzę do bazy danych library by po chwili z najdzikszą rozkoszą sięgającą granic pojmowania ludzkiego umysłu tworzę tabelę o przebiegłej nazwie books. Tabela ta zawiera pole id będące kluczem typu unsigned int z ustawioną opcją automatycznego przyrostu wartości przy dodawaniu rekordów do bazy danych. Kolejne pola tej tabeli to title i author, których maksymalna długość może osiągnąć zawrotną wartość 255 znaków. Po utworzeniu w tak żmudnym procesie tabeli niezwłocznie należy oddać się dzikiej rozkoszy dodania do niej jednej pozycji książkowej, co też i czynię w linijce piętnastej.
Baza danych - pierwszy kontakt
Oczywiście do utworzenia bazy danych jak i połączenia się z nią konieczna jest obecność w systemie uruchomionego serwera SQL w moim przypadku używam XAMPP-a, który zainstalował mi cały pakiet tego, co potrzebne jest do uruchomienia serwera SQL na localhost. W moim przypadku połączenie uzyskam wykorzystując następujący kod w pliku mainwindow.h:
- #ifndef MAINWINDOW_H
- #define MAINWINDOW_H
- #include <QMainWindow>
- #include <QDebug>
- #include <QMessageBox>
- #include <QStringList>
- #include <QSqlDatabase>
- #include <QSqlError>
- #include <QSqlQuery>
- #include <mysql.h>
- namespace Ui {
- class MainWindow;
- }
- class MainWindow : public QMainWindow
- {
- Q_OBJECT
- QSqlDatabase db;
- void readRecordsToListWidget();
- public:
- explicit MainWindow(QWidget *parent = 0);
- ~MainWindow();
- private slots:
- void on_btAdd_clicked();
- void on_records_doubleClicked(const QModelIndex &index);
- void on_btRemove_clicked();
- private:
- Ui::MainWindow *ui;
- };
- #endif // MAINWINDOW_H
W pliku mainwindow.cpp:
- #include "mainwindow.h"
- #include "ui_mainwindow.h"
- // https://dev.mysql.com/downloads/connector/c/
- MainWindow::MainWindow(QWidget *parent) :
- QMainWindow(parent),
- ui(new Ui::MainWindow)
- {
- ui->setupUi(this);
- db = QSqlDatabase::addDatabase("QMYSQL"); // tworzę bazę danych z wykorzystaniem sterownika QMYSQL
- db.setDatabaseName("library"); // ustawiam nazwę biblioteki, pod którą chcę się podpiąć
- db.setHostName("localhost"); // nazwa serwera
- db.setPassword("password"); // hasło gienka
- db.setPort(3306); // port połączenia z bazą danych
- db.setUserName("gienek"); // nazwa użytkownika
- if(!db.open()){ // próbuję otworzyć bazę danych i jak się nie otworzy to
- qDebug() << "ERROR load: " << db.lastError().text(); // wyświetlam błąd ładowania w konsoli kompilatora
- }else{
- qDebug() << "Is opened"; // wszystko cacy
- readRecordsToListWidget(); // więc wczytuję dane do mojej kontrolki QListWidget
- }
- }
- void MainWindow::readRecordsToListWidget(){
- QSqlQuery query(db); // tworzę obiekt zapytania i podpinam go pod otwartą bazę danych
- ui->records->clear(); // usuwam wszystkie elementy kontrolki
- if(query.exec("SELECT id, title, author FROM books")){ // wysyłam zapytanie do bazy danych
- while(query.next()){ // jeżeli są jakieś wyniki to
- // wstawiam rekord do kontrolki QListWidget
- ui->records->addItem(new QListWidgetItem(query.value(0).toString() + " \"" + query.value(1).toString() + "\" " + query.value(2).toString(), ui->records));
- }
- }else{
- qDebug() << query.lastError().text(); // wyświetlam w konsoli Qt Creatora informację błędu, gdy zapytanie zakończy się niepowodzeniem
- }
- }
- MainWindow::~MainWindow()
- {
- delete ui;
- }
- void MainWindow::on_btAdd_clicked() // dodawanie elementu do bazy danych
- {
- // sprawdzanie, czy kontrolki edAuthor i edTitle nie zawierają niedozwolonych znaków
- if(ui->edAuthor->text().indexOf("\"") != -1){
- ui->edAuthor->setText( ui->edAuthor->text().replace("\"", "") );
- QMessageBox::information(this, "Ostrzeżenie", "Pole autora książki zawierało niedozwolony znak \", który został usunięty");
- }
- if(ui->edTitle->text().indexOf("\"") != -1){
- ui->edTitle->setText( ui->edTitle->text().replace("\"", "") );
- QMessageBox::information(this, "Ostrzeżenie", "Pole tytułu książki zawierało niedozwolony znak \", który został usunięty");
- }
- if(ui->edAuthor->text().size() && ui->edTitle->text().size()){ // jeżeli pola tekstowe nie są puste to
- QSqlQuery query(db); // tworzę obiekt zapytania
- // przygotowuję zapytanie SQL, sprawdzające, czy w bazie danych jest już książka o podanym tytule i autorze
- query.prepare("SELECT title, author FROM books WHERE title = :title AND author = :author LIMIT 1;");
- // podpinam pod nie dane
- query.bindValue(":title", QVariant::fromValue(ui->edTitle->text())); // tekst z kontrolki edTitle zostanie oddzielnie wysłany a następnie wstawiony do zapytania za :title
- query.bindValue(":author", QVariant::fromValue(ui->edAuthor->text())); // to samo co powyżej
- if(
- query.exec() && (!query.next() // jak zapytanie zakończyło się powodzeniem i zwróciło element lub użytkownik postanowił dodać zduplikowany rekord to
- ||
- QMessageBox::warning( // jeżeli
- this,
- "Ostrzeżenie",
- "Autor i tytuł już istnieje na liście, czy chcesz"
- " mimo to dodać tę pozycję ponownie?",
- QMessageBox::Yes | QMessageBox::No
- ) == QMessageBox::Yes)){
- // przygotowuję nowe zapytanie
- query.prepare("INSERT INTO books (title, author) VALUES (:title, :author);");
- // binduję wartości
- query.bindValue(":title", QVariant::fromValue(ui->edTitle->text()));
- query.bindValue(":author", QVariant::fromValue(ui->edAuthor->text()));
- // wykonuję zapytanie
- if(query.exec()){
- readRecordsToListWidget(); // i jeżeli zakończy się ono powodzeniem to odświerzam listę rekordów
- }
- }
- }
- }
- void MainWindow::on_records_doubleClicked(const QModelIndex &index) // zdarzenie kliknięcia dwukrotnego w oknie kontrolki
- {
- QString recordData = index.data().toString();
- QStringList record = recordData.split(" \"");
- QStringList record2 = record[1].split("\" ");
- record.removeAt(1);
- record += record2;
- if(record.size() == 3){
- ui->edTitle->setText(record[1]); // wczytuję rekord do kontrolki tytułu
- ui->edAuthor->setText(record[2]); // wczytuję rekord do kontrolki autora
- }
- }
- void MainWindow::on_btRemove_clicked() // zdarzenie kliknięcia przycisku usunięcia zaznaczonego elementu
- {
- if(ui->records->currentItem()){
- QString recordData = ui->records->currentItem()->data(Qt::DisplayRole).toString();
- QStringList record = recordData.split(" \"");
- bool ok = false;
- int index = record[0].toInt(&ok);
- if(ok){
- QSqlQuery query(db);
- query.prepare("DELETE FROM books WHERE id = :id;"); // zapytanie usuwające wybrany rekord
- query.bindValue(":id", index);
- if(query.exec()){
- readRecordsToListWidget();
- }else{
- qDebug() << query.lastError();
- }
- }
- }
- }
Poniżej można zobaczyć screen programu umożliwiającego dodawanie i usuwanie rekordów z bazy danych.


Tytuł:
Architektura oprogramowania bez tajemnic. Wykorzystaj język C++ do tworzenia wydajnych aplikacji i systemów
Autor:
Adrian Ostrowski, Piotr Gaczkowski

Tytuł:
Opus magnum C++ 11. Programowanie w języku C++. Wydanie II poprawione (komplet)
Autor:
Jerzy Grębosz

Tytuł:
Programowanie wieloplatformowe z C++ i wxWidgets 3
Autor:
Bartosz W. Warzocha

Tytuł:
Język C++ i przetwarzanie współbieżne w akcji. Wydanie II
Autor:
Anthony Williams

Tytuł:
C++ dla bystrzaków. Wydanie VII
Autor:
Stephen R. Davis

Tytuł:
Tablice informatyczne. Podstawy C++
Autor:
Radosław Sokół

Tytuł:
Opus magnum C++11. Programowanie w języku C++ (komplet)
Autor:
Jerzy Grębosz

Tytuł:
OpenCV 3. Komputerowe rozpoznawanie obrazu w C++ przy użyciu biblioteki OpenCV
Autor:
Adrian Kaehler, Gary Bradski

Tytuł:
C++ w 24 godziny. Wydanie VI
Autor:
Rogers Cadenhead, Jesse Liberty

Tytuł:
C++ Optymalizacja kodu. Sprawdzone techniki zwiększania wydajności
Autor:
Guntheroth Kurt