Nouveau : Datasets open source gratuits disponibles !Decouvrir →
🦀
Intermediaire 30 min Rust

Rust avec PostgreSQL : guide pratique

Pourquoi Rust avec PostgreSQL : guide pratique ?

Contexte réel : pourquoi un dev a besoin de ca au quotidien

Au sein d'un environnement professionnel, la gestion de données est cruciale pour l'efficacité et la performance des applications. PostgreSQL, une base de données relationnelle puissante et fiable, offre des fonctionnalités avancées qui sont essentielles dans un contexte moderne du développement.

Un cas d'utilisation concret serait une application e-commerce. La gestion efficace de millions de produits, des commandes et des utilisateurs nécessite une base de données robuste. Rust, avec son modèle de programmation concurrente sécurisé et sa performance élevée, est idéal pour construire un backend performant qui peut traiter une grande charge de travail en temps réel.

Prerequis

  • Connaissance de base de Rust
  • Familiarité avec les bases de données SQL
  • Installation de PostgreSQL
  • Un environnement de développement (par exemple, Visual Studio Code avec des extensions Rust)

Concepts fondamentaux

1. Connexion à la Base de Données

Pour interagir avec PostgreSQL en Rust, nous utilisons le crate tokio-postgres. Voici comment vous pouvez vous connecter à une base de données :

use tokio_postgres::{NoTls, Error};

#[tokio::main]
async fn main() -> Result<(), Error> {
    // Connexion à la base de données PostgreSQL
    let (client, connection) = tokio_postgres::connect("host=localhost user=postgres password=secret dbname=mydb", NoTls).await?;

    // Lancement du thread pour gérer les connexions
    tokio::spawn(async move {
        if let Err(e) = connection.await {
            eprintln!("connection error: {}", e);
        }
    });

    Ok(())
}

2. Exécution de Requêtes

Une fois connecté à la base de données, vous pouvez exécuter des requêtes SQL :

use tokio_postgres::{NoTls, Error};

#[tokio::main]
async fn main() -> Result<(), Error> {
    let (client, connection) = tokio_postgres::connect("host=localhost user=postgres password=secret dbname=mydb", NoTls).await?;

    tokio::spawn(async move {
        if let Err(e) = connection.await {
            eprintln!("connection error: {}", e);
        }
    });

    // Exécution d'une requête SQL
    let rows = client.query("SELECT id, name FROM users WHERE age > $1", &[&20]).await?;

    for row in rows {
        let id: i32 = row.get(0);
        let name: String = row.get(1);
        println!("User ID: {}, Name: {}", id, name);
    }

    Ok(())
}

3. Insertion de Données

Vous pouvez également insérer des données dans la base de données :

use tokio_postgres::{NoTls, Error};

#[tokio::main]
async fn main() -> Result<(), Error> {
    let (client, connection) = tokio_postgres::connect("host=localhost user=postgres password=secret dbname=mydb", NoTls).await?;

    tokio::spawn(async move {
        if let Err(e) = connection.await {
            eprintln!("connection error: {}", e);
        }
    });

    // Insertion de données
    client.execute(
        "INSERT INTO users (name, age) VALUES ($1, $2)",
        &[&"John Doe", &30],
    ).await?;

    Ok(())
}

4. Mise à jour et Suppression

Mettre à jour et supprimer des données est également possible :

use tokio_postgres::{NoTls, Error};

#[tokio::main]
async fn main() -> Result<(), Error> {
    let (client, connection) = tokio_postgres::connect("host=localhost user=postgres password=secret dbname=mydb", NoTls).await?;

    tokio::spawn(async move {
        if let Err(e) = connection.await {
            eprintln!("connection error: {}", e);
        }
    });

    // Mise à jour de données
    client.execute(
        "UPDATE users SET age = $1 WHERE name = $2",
        &[&35, &"John Doe"],
    ).await?;

    // Suppression de données
    client.execute(
        "DELETE FROM users WHERE name = $1",
        &[&"John Doe"],
    ).await?;

    Ok(())
}

Mise en pratique : projet fil rouge

Étape 1 : Configuration du Projet

Créez un nouveau projet Rust :

cargo new rust_postgres_tutorial --bin
cd rust_postgres_tutorial

Ajoutez les dépendances nécessaires dans Cargo.toml :

[dependencies]
tokio = { version = "1", features = ["full"] }
tokio-postgres = "0.7"

Étape 2 : Structure du Projet

Créez une structure de fichiers simple :

src/
├── main.rs
└── db/
    └── connection.rs

Étape 3 : Connexion à la Base de Données

Ajoutez le code pour se connecter à la base de données dans db/connection.rs :

use tokio_postgres::{NoTls, Error};

pub async fn establish_connection() -> Result<tokio_postgres::Client, Error> {
    let (client, connection) = tokio_postgres::connect("host=localhost user=postgres password=secret dbname=mydb", NoTls).await?;
    tokio::spawn(async move {
        if let Err(e) = connection.await {
            eprintln!("connection error: {}", e);
        }
    });
    Ok(client)
}

Étape 4 : Création des Tables

Ajoutez du code pour créer les tables nécessaires dans db/schema.sql :

CREATE TABLE IF NOT EXISTS users (
    id SERIAL PRIMARY KEY,
    name VARCHAR(100) NOT NULL,
    age INT NOT NULL
);

Créez un script pour exécuter la création des tables :

psql -h localhost -U postgres -d mydb -f db/schema.sql

Étape 5 : Insertion de Données

Ajoutez du code pour insérer des données dans src/main.rs :

use crate::db;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = db::establish_connection().await?;

    // Insertion de données
    client.execute(
        "INSERT INTO users (name, age) VALUES ($1, $2)",
        &[&"John Doe", &30],
    ).await?;

    Ok(())
}

Étape 6 : Mise à jour et Suppression

Ajoutez du code pour mettre à jour et supprimer des données dans src/main.rs :

use crate::db;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = db::establish_connection().await?;

    // Mise à jour de données
    client.execute(
        "UPDATE users SET age = $1 WHERE name = $2",
        &[&35, &"John Doe"],
    ).await?;

    // Suppression de données
    client.execute(
        "DELETE FROM users WHERE name = $1",
        &[&"John Doe"],
    ).await?;

    Ok(())
}

Erreurs fréquentes et debugging

1. Connexion échoue

## ❌ Mauvais
let (client, connection) = tokio_postgres::connect("host=localhost user=postgres dbname=mydb", NoTls).await?;

## ✅ Correct
let (client, connection) = tokio_postgres::connect("host=localhost user=postgres password=secret dbname=mydb", NoTls).await?;

2. Exécution de requêtes échoue

## ❌ Mauvais
let rows = client.query("SELECT id, name FROM users WHERE age > $1", &[&20]).await?;

## ✅ Correct
let rows = client.query("SELECT id, name FROM users WHERE age > $1", &[&20]).await?;

3. Insertion de données échoue

## ❌ Mauvais
client.execute(
    "INSERT INTO users (name, age) VALUES ($1, $2)",
    &[&"John Doe", &30],
).await?;

## ✅ Correct
client.execute(
    "INSERT INTO users (name, age) VALUES ($1, $2)",
    &[&"John Doe", &30],
).await?;

Pour aller plus loin

1. Transactions

Les transactions sont essentielles pour assurer l'intégrité des données. Voici comment vous pouvez les gérer :

use tokio_postgres::{NoTls, Error};

#[tokio::main]
async fn main() -> Result<(), Error> {
    let (client, connection) = tokio_postgres::connect("host=localhost user=postgres password=secret dbname=mydb", NoTls).await?;

    tokio::spawn(async move {
        if let Err(e) = connection.await {
            eprintln!("connection error: {}", e);
        }
    });

    // Début d'une transaction
    let mut tx = client.transaction().await?;

    // Exécution de requêtes dans la transaction
    tx.execute(
        "INSERT INTO users (name, age) VALUES ($1, $2)",
        &[&"John Doe", &30],
    ).await?;

    tx.commit().await?;

    Ok(())
}

2. Migration

La gestion des migrations de base de données est cruciale pour le développement en équipe et la maintenance. Utilisez flyway ou Liquibase pour gérer les migrations.

3. ORM

Pour un développement plus facile, vous pouvez utiliser des ORMs comme diesel :

[dependencies]
diesel = { version = "1.4", features = ["postgres"] }
dotenv = "0.15"

Créez un fichier .env pour les variables d'environnement :

DATABASE_URL=postgres://postgres:secret@localhost/mydb

Défi pratique

Construire une application simple qui permet de gérer des tâches (ajouter, mettre à jour, supprimer, afficher). Utilisez les concepts appris et ajoutez des fonctionnalités supplémentaires comme la gestion des utilisateurs.


Ce tutoriel a couvert les bases de l'utilisation de Rust avec PostgreSQL, en abordant la connexion à la base de données, l'exécution de requêtes SQL, l'insertion, la mise à jour et la suppression de données. Il a également montré comment mettre en œuvre des transactions et donner une introduction aux ORMs pour faciliter le développement.

Besoin d'aide sur Rust ?

Besoin d'aide sur un projet technique ? Decrivez-le pour des conseils personnalises.

Recevoir des conseils

Questions frequentes

Comment installer les dépendances nécessaires pour utiliser PostgreSQL avec Rust ?
Pour installer les dépendances nécessaires, vous devez d'abord installer le crate `tokio-postgres` et `postgres`. Vous pouvez les ajouter à votre fichier `Cargo.toml` en utilisant `[dependencies] tokio-postgres = "0.7" postgres = "0.19".
Comment se connecter à une base de données PostgreSQL depuis un programme Rust ?
Pour vous connecter à une base de données PostgreSQL, utilisez la fonction `tokio_postgres::connect` en passant les informations d'identification (host, port, utilisateur, mot de passe et nom de la base). La fonction retourne un tuple contenant le client et l'erreur.
Comment exécuter une requête SQL et récupérer les résultats dans Rust ?
Pour exécuter une requête SQL, utilisez la méthode `query` du client PostgreSQL. Elle prend en paramètre la chaîne de requête SQL et retourne un résultat qui peut être itéré pour obtenir chaque ligne.

Pages liees

Chaque semaine, le meilleur de la tech francaise

Tendances, salaires, outils et opportunites — directement dans votre boite mail.

Gratuit. Desabonnement en un clic. Pas de spam.