Autor podstrony: Krzysztof Zajączkowski

Stronę tą wyświetlono już: 5921 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() + " \apos" + query.value(1).toString() + "\apos " + 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("\apos") != -1){ ui->edAuthor->setText( ui->edAuthor->text().replace("\apos", "") ); QMessageBox::information(this, "Ostrzeżenie", "Pole autora książki zawierało niedozwolony znak \apos, który został usunięty"); } if(ui->edTitle->text().indexOf("\apos") != -1){ ui->edTitle->setText( ui->edTitle->text().replace("\apos", "") ); QMessageBox::information(this, "Ostrzeżenie", "Pole tytułu książki zawierało niedozwolony znak \apos, 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(" \apos"); QStringList record2 = record[1].split("\apos "); 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(" \apos"); 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.

Przykład programu łączącego się z bazą danych MySQL
Rys. 1
Przykład programu łączącego się z bazą danych MySQL na localhoście
Strony powiązane
strony powiązane
  1. doc.qt.io/qt-5/qsqldatabase.html - opis kasy QSqlDatabase na stronie dokumentacji Qt
  2. doc.qt.io/qt-4.8/qsqlquery.html - opis kasy QSqlQuery na stronie dokumentacji Qt
Layout wykonany przez autora strony, wszelkie prawa zastrzeżone. Jakiekolwiek użycie części lub całości grafik znajdujących się na tej stronie bez pisemnej zgody jej autora surowo zabronione.