Qt pour les Bases De Données

Présentation générale

L’accès à une BDD dans Qt se fait via le module Qt SQL, qui permet de se connecter à différents SGBD (SQLite, MySQL, PostgreSQL…​) et de les exploiter à travers l'API (ensemble de classes/méthodes C++) qu’il propose.

L’API du module SQL repose sur des drivers pour offrir une interface unifiée aux différents SGBDs.

Exploitation d’une BDD depuis Qt

Ci-dessous figurent un résumé des étapes à suivres pour exploiter une BDD.

Inclusion du module SQL de Qt

Pour utiliser les fonctionnalités SQL, il faut inclure le module dans le projet Qt :

  • Dans le fichier .pro :

    [...]
    QT += sql
    [...]
  • Dans le code C++ :

    [...]
    #include <QtSql>
    [...]

Installation du driver SQL

Qt propose plusieurs drivers. Les plus courants sont :

  • SQLite : simple, aucun serveur requis.

  • MySQL : plus de fonctionnalités (accès concurrents, multi-utilisateurs, procédures stockées, réplication…​).
    Requiert l’installation du serveur MySQL.

Installation (exemple sous Qt5 Linux) :

  • Pour SQLite :

    sudo apt install sqlite3 (1)
    sudo apt install libqt5sql5-sqlite (2)
    1 Installation de l’interface en ligne de commande + librairie SQLite
    2 Installation du driver Qt SQLite (souvent installé par défaut)
  • Pour MySQL : installer le package libqt5sql5-mysql.

    sudo apt install mysql-server (1)
    sudo apt install libqt5sql5-mysql (2)
    1 Installation du serveur MySQL
    2 Installation du driver Qt MySQL

Les drivers (→ libsqlite.so, libqsqlmysql.so) sont installés dans /usr/lib/x86_64-linux-gnu/qt5/plugins/sqldrivers/ dans Ubuntu.

Connexion à la base de données

  • Exemple SQLite (BDD locale, pas de mot de passe) :

    QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
    db.setDatabaseName("donnees.db"); // chemin du fichier local
    if(!db.open()) {
       qDebug() << "Erreur SQLite:" << db.lastError().text();
    }
  • Exemple MySQL (BDD distante, avec login/mot de passe) :

    QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL");
    db.setHostName("adresse_serveur");      // ex: "192.168.1.10"
    db.setPort(3306);                       // port par défaut
    db.setDatabaseName("nom_base");
    db.setUserName("utilisateur");
    db.setPassword("votre_mot_de_passe");
    if(!db.open()) {
       qDebug() << "Erreur MySQL:" << db.lastError().text();
    }

    Pour se connecter à distance, le serveur MySQL doit autoriser les connexions distantes et l’utilisateur doit avoir les droits adaptés.

Élaboration et exécution de requêtes SQL

Le code est identique pour SQLite et MySQL.

  • Requête SQL simple :

    QSqlQuery query;
    if (query.exec("SELECT * FROM clients")) {
        // traitement plus loin
    } else {
        qDebug() << query.lastError().text();
    }
  • Requête préparée (prévention des injections SQL) :

    QSqlQuery query;
    query.prepare("SELECT * FROM clients WHERE nom = :nom");
    query.bindValue(":nom", "Dupont");
    if (query.exec()) {
        // traitement plus loin
    } else {
        qDebug() << query.lastError().text();
    }

Exploitation du résultat d’une requête SQL

Le résultat d’exécution d’une requête SQL se nomme un resulset.

On accède aux enregistrements de ce resulset via un curseur.

Le code est identique pour SQLite et MySQL.

while(query.next()) {
    int id = query.value(0).toInt();
    QString nom = query.value("nom").toString();
    // ...
}

Fermeture de la connexion à la BDD

db.close();

Exemple complet

Ce programme propose une connexion à SQLite ou MySQL selon vos besoins.

#include <QCoreApplication>
#include <QtSql>
#include <QDebug>

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);

    // === CHOISIR LE MODE DE BASE ===
    bool utiliserMySQL = false; // Mettre à true pour tester MySQL

    QSqlDatabase db;
    if(utiliserMySQL) {
        db = QSqlDatabase::addDatabase("QMYSQL");
        db.setHostName("adresse_serveur"); // à adapter
        db.setPort(3306);
        db.setDatabaseName("nom_base");
        db.setUserName("utilisateur");
        db.setPassword("motdepasse");
    } else {
        db = QSqlDatabase::addDatabase("QSQLITE");
        db.setDatabaseName("donnees.db");
    }

    if(!db.open()) {
        qDebug() << "Erreur d'ouverture:" << db.lastError().text();
        return 1;
    }

    // === REQUÊTE SIMPLE ===
    QSqlQuery query;
    if(query.exec("SELECT id, nom FROM clients")) {
        while(query.next()) {
            int id = query.value("id").toInt();
            QString nom = query.value("nom").toString();
            qDebug() << "ID:" << id << "Nom:" << nom;
        }
    } else {
        qDebug() << "Erreur (requête simple):" << query.lastError().text();
    }

    // === REQUÊTE PRÉPARÉE ===
    query.prepare("SELECT * FROM clients WHERE nom = :nom");
    query.bindValue(":nom", "Dupont");
    if(query.exec()) {
        while(query.next()) {
            qDebug() << "Résultat préparée:" << query.value("nom").toString();
        }
    } else {
        qDebug() << "Erreur (requête préparée):" << query.lastError().text();
    }

    db.close();
    return 0;
}

Points clés

  • Adapter le nom du driver selon le type de base.

  • Pour MySQL vérifier le port, le hostname, le login/mot de passe.

  • Toujours vérifier le retour de lastError() en cas d’échec.

  • Les requêtes préparées sont indispensables pour la sécurité.

Ressources

Annexes

Configuration de MySQL

  • Configurer mot de passe root

    $ sudo mysql
    mysql> ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'mysqladmin';
    Query OK, 0 rows affected (0,02 sec)
    
    mysql> FLUSH PRIVILEGES;
    Query OK, 0 rows affected (0,01 sec)
    
    mysql> SELECT user, plugin FROM mysql.user;
    +------------------+-----------------------+
    | user             | plugin                |
    +------------------+-----------------------+
    | debian-sys-maint | caching_sha2_password |
    | mysql.infoschema | caching_sha2_password |
    | mysql.session    | caching_sha2_password |
    | mysql.sys        | caching_sha2_password |
    | root             | mysql_native_password |
    +------------------+-----------------------+
    5 rows in set (0,00 sec)
    
    mysql> exit
  • Créer un nouvel utilisateur MySQL :

    $ mysql -u root -p
    
    mysql> SHOW VARIABLES LIKE 'validate_password%'; (1)
    +-------------------------------------------------+--------+
    | Variable_name                                   | Value  |
    +-------------------------------------------------+--------+
    | validate_password.changed_characters_percentage | 0      |
    | validate_password.check_user_name               | ON     |
    | validate_password.dictionary_file               |        |
    | validate_password.length                        | 8      |
    | validate_password.mixed_case_count              | 1      |
    | validate_password.number_count                  | 1      |
    | validate_password.policy                        | MEDIUM |
    | validate_password.special_char_count            | 1      |
    +-------------------------------------------------+--------+
    8 rows in set (0,01 sec)
    
    mysql> CREATE USER 'ragnar'@'%' IDENTIFIED WITH mysql_native_password BY 'V@lh@ll@4m3!'; (2)
    Query OK, 0 rows affected (0,01 sec)
    
    mysql> exit
    Bye
    1 Affichage politique de mot de passe ⇒ 8+ caractères ET majuscules/minuscules ET chiffres ET caractères spéciaux
    2 Cration utilisateur “ragnar” avec mot de passe en accord avec la politique de sécurité (→ “V@lh@ll@4m3!”)
  • Créer une BDD accessible à l’utilisateur nouvellement créé :

    $ mysql -u root -p
    
    mysql> CREATE DATABASE dbvikings; (1)
    Query OK, 1 row affected (0,03 sec)
    
    mysql> GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, INDEX, DROP, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES ON dbvikings.* TO 'ragnar'@'%'; (2)
    Query OK, 0 rows affected (0,01 sec)
    
    mysql>
    1 Création BDD
    2 Attribution des droits SELECT, UPDATE …​ à l’utilisateur “ragnar” connecté depuis n’importe quelle IP (→ '%')
  • Autoriser un accès distant à MySQL en modifiant /etc/mysql/mysql.conf.d/mysql.cnf :

    # If MySQL is running as a replication slave, this should be
    # changed. Ref https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.html#sysvar_tmpdir
    # tmpdir                = /tmp
    #
    # Instead of skip-networking the default is now to listen only on
    # localhost which is more compatible and is not less secure.
    bind-address            = #192.168.5.12(1)
    mysqlx-bind-address     = 127.0.0.1
    1 Mettre IP de la VM LUbuntu ou de la Raspberry Pi
  • Redémarrer le service avec :

    sudo systemctl restart mysql.service
  • Autoriser l’accès à MySQL dans le firewall :

    $ sudo ufw allow mysql
    La règle a été ajoutée
    La règle a été ajoutée (v6)

🕮 Liens :


🞄  🞄  🞄