Learn Rust Coding · Lezione

Integrazione con i database (SQLx/Diesel)

Integri il Suo servizio web Rust con i database utilizzando ORM o query builder diffusi come SQLx o Diesel.

Lezione 2 di 311 passaggi

Integrazione con i database (SQLx/Diesel) è una lezione Learn Rust Coding gratuita su CoddyKit. Questa è la lezione 2 di 3. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento Learn Rust Coding, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso Learn Rust Coding include 3 lezioni in totale.

Perché usare database per il web?

I servizi web spesso devono memorizzare e recuperare i dati in modo persistente. Pensi ai profili degli utenti, ai cataloghi di prodotti o agli articoli di un blog: questi dati devono risiedere in un luogo diverso dalla memoria del programma.

I database offrono un modo strutturato per gestire questi dati, garantendo che siano sicuri, coerenti e accessibili. Integrare il servizio web Rust con un database è un'attività fondamentale per la maggior parte delle applicazioni reali.

SQLx: il Suo alleato asincrono per i database

In Rust disponiamo di strumenti eccellenti per interagire con i database. Due opzioni molto diffuse sono SQLx e Diesel.

  • SQLx: un crate SQL asincrono, scritto interamente in Rust, con query verificate in fase di compilazione. È spesso preferito per i servizi web asincroni creati con framework come Tokio.
  • Diesel: un potente ORM (Object-Relational Mapper) che offre un modo più astratto di interagire con il database, mappando direttamente le struct Rust nelle tabelle del database. In genere è sincrono.

In questa lezione ci concentreremo su SQLx per il suo solido supporto asincrono, particolarmente adatto allo sviluppo moderno di servizi web Rust.

Configurazione di SQLx: dipendenze

Prima di scrivere il codice, deve aggiungere sqlx e tokio al file Cargo.toml del progetto. tokio fornisce il runtime asincrono richiesto da sqlx.

Ad esempio, per usare SQLite (un database basato su file, semplice da usare nello sviluppo locale) con SQLx, il file Cargo.toml potrebbe avere questo aspetto:

[dependencies] sqlx = { version = "0.7", features = ["runtime-tokio-rustls", "sqlite"] } tokio = { version = "1", features = ["full"] }

In genere userà anche una variabile d'ambiente DATABASE_URL per configurare la stringa di connessione al database.

Connettersi al primo database

Stabiliamo una connessione a un database SQLite in memoria. SQLx usa pool di connessioni, che gestiscono in modo efficiente più connessioni al database per gestire le richieste concorrenti del servizio web.

Provi a eseguire questo esempio:

use sqlx::SqlitePool;
use tokio;

#[tokio::main]
async fn main() -> Result<(), sqlx::Error> {
    // Use an in-memory SQLite database for simplicity
    let database_url = "sqlite::memory:"; 
    let pool = SqlitePool::connect(&database_url).await?;
    println!("Successfully connected to the database!");

    // In a real web app, 'pool' would be passed around or stored in app state.

    Ok(())
}

Strutturare i dati con le tabelle

Prima di poter memorizzare i dati, dobbiamo definire lo schema del database usando il DDL (Data Definition Language). Creiamo una semplice tabella tasks.

La macro sqlx::query! consente di incorporare direttamente SQL nel codice Rust. Esegue persino controlli sulle istruzioni SQL in fase di compilazione!

use sqlx::{SqlitePool, query};
use tokio;

#[tokio::main]
async fn main() -> Result<(), sqlx::Error> {
    let database_url = "sqlite::memory:";
    let pool = SqlitePool::connect(&database_url).await?;

    // Create a 'tasks' table if it doesn't exist
    query!(
        "CREATE TABLE IF NOT EXISTS tasks (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            description TEXT NOT NULL,
            completed BOOLEAN NOT NULL DEFAULT FALSE
        )"
    ).execute(&pool).await?;

    println!("Table 'tasks' created successfully!");
    Ok(())
}

Aggiungere nuovi record

Ora che abbiamo una tabella, aggiungiamo alcuni dati! Useremo l'istruzione INSERT con il binding dei parametri. Questo protegge dagli attacchi di SQL injection e rende più sicure le query.

Noti che per i parametri vengono usati i segnaposto ? e che i valori vengono passati a .bind().

use sqlx::{SqlitePool, query};
use tokio;

#[tokio::main]
async fn main() -> Result<(), sqlx::Error> {
    let database_url = "sqlite::memory:";
    let pool = SqlitePool::connect(&database_url).await?;

    query!(
        "CREATE TABLE IF NOT EXISTS tasks (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            description TEXT NOT NULL,
            completed BOOLEAN NOT NULL DEFAULT FALSE
        )"
    ).execute(&pool).await?;

    // Insert a new task
    let description = "Learn SQLx";
    let completed = false;
    query!(
        "INSERT INTO tasks (description, completed) VALUES (?, ?)",
        description,
        completed
    ).execute(&pool).await?;

    println!("Task '{}' inserted successfully!", description);
    Ok(())
}

Recuperare i dati con SELECT

Per recuperare i dati dalla tabella tasks, usiamo l'istruzione SELECT. SQLx fornisce metodi come .fetch_all() o .fetch_one() per ottenere i risultati.

Può scorrere le righe restituite e accedere alle colonne tramite nome o indice.

use sqlx::{SqlitePool, query};
use tokio;

#[tokio::main]
async fn main() -> Result<(), sqlx::Error> {
    let database_url = "sqlite::memory:";
    let pool = SqlitePool::connect(&database_url).await?;

    query!(
        "CREATE TABLE IF NOT EXISTS tasks (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            description TEXT NOT NULL,
            completed BOOLEAN NOT NULL DEFAULT FALSE
        )"
    ).execute(&pool).await?;

    query!(
        "INSERT INTO tasks (description, completed) VALUES (?, ?)",
        "Learn SQLx", false
    ).execute(&pool).await?;
    query!(
        "INSERT INTO tasks (description, completed) VALUES (?, ?)",
        "Build a web app", false
    ).execute(&pool).await?;

    // Fetch and print all tasks
    println!("\n--- All Tasks ---");
    let rows = query!("SELECT id, description, completed FROM tasks")
        .fetch_all(&pool).await?;

    for row in rows {
        println!("ID: {}, Desc: {}, Done: {}", 
            row.id, row.description, row.completed);
    }
    Ok(())
}

Dati type-safe con le struct

Estrarre manualmente i dati dalle righe può causare errori. La macro query_as! di SQLx, combinata con #[derive(FromRow)], consente di mappare direttamente i risultati delle query nelle struct Rust!

Questo offre una forte sicurezza dei tipi e rende il codice molto più chiaro e semplice da gestire.

use sqlx::{FromRow, SqlitePool, query, query_as};
use tokio;

#[derive(Debug, FromRow)]
struct Task {
    id: i64,
    description: String,
    completed: bool,
}

#[tokio::main]
async fn main() -> Result<(), sqlx::Error> {
    let database_url = "sqlite::memory:";
    let pool = SqlitePool::connect(&database_url).await?;

    query!(
        "CREATE TABLE IF NOT EXISTS tasks (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            description TEXT NOT NULL,
            completed BOOLEAN NOT NULL DEFAULT FALSE
        )"
    ).execute(&pool).await?;

    query!(
        "INSERT INTO tasks (description, completed) VALUES (?, ?)",
        "Learn SQLx", false
    ).execute(&pool).await?;

    // Fetch tasks directly into our Task struct
    println!("\n--- Tasks as Structs ---");
    let tasks = query_as::<_, Task>("SELECT id, description, completed FROM tasks")
        .fetch_all(&pool).await?;

    for task in tasks {
        println!("{:?}", task);
    }
    Ok(())
}

Modificare ed eliminare record

L'aggiornamento e l'eliminazione dei dati seguono uno schema simile all'inserimento. Si usano le istruzioni SQL UPDATE e DELETE con il binding dei parametri.

  • UPDATE: modifica le righe esistenti in base a una clausola WHERE.
  • DELETE: rimuove le righe in base a una clausola WHERE.

Presti sempre attenzione alle clausole WHERE in UPDATE e DELETE per evitare perdite di dati involontarie!

use sqlx::{SqlitePool, query};
use tokio;

#[tokio::main]
async fn main() -> Result<(), sqlx::Error> {
    let database_url = "sqlite::memory:";
    let pool = SqlitePool::connect(&database_url).await?;

    query!(
        "CREATE TABLE IF NOT EXISTS tasks (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            description TEXT NOT NULL,
            completed BOOLEAN NOT NULL DEFAULT FALSE
        )"
    ).execute(&pool).await?;

    query!(
        "INSERT INTO tasks (description, completed) VALUES (?, ?)",
        "Finish lesson", false
    ).execute(&pool).await?;
    let task_id_to_update = 1;

    // Update a task
    query!(
        "UPDATE tasks SET completed = ? WHERE id = ?",
        true,
        task_id_to_update
    ).execute(&pool).await?;
    println!("Task {} updated.", task_id_to_update);

    // Delete a task (uncomment to run, careful with IDs after update)
    // let task_id_to_delete = 1;
    // query!(
    //     "DELETE FROM tasks WHERE id = ?",
    //     task_id_to_delete
    // ).execute(&pool).await?;
    // println!("Task {} deleted.", task_id_to_delete);

    Ok(())
}

Verifichi le Sue competenze sui database

Quali delle seguenti affermazioni su SQLx nei servizi web Rust sono VERE?

Integrazione dei database: punti chiave

Ha compiuto un passo importante nella creazione di servizi web Rust robusti imparando a integrare i database!

  • Persistenza: i database sono fondamentali per memorizzare i dati delle applicazioni.
  • SQLx: un crate SQL asincrono, verificato in fase di compilazione, ideale per i servizi web.
  • Pool di connessioni: essenziali per un accesso al database efficiente e concorrente.
  • CRUD: abbiamo visto come creare (INSERT), recuperare (SELECT), aggiornare (UPDATE) ed eliminare (DELETE) i dati.
  • Sicurezza dei tipi: query_as! e #[derive(FromRow)] consentono una mappatura dei dati sicura ed ergonomica.

Ora può esplorare l'integrazione di queste operazioni sui database nelle route web reali!

Gratis per iniziare

Impara Rust con un tutor IA — gratis

Scrivi ed esegui vero codice nel tuo browser, ricevi aiuto istantaneo da un tutor IA disponibile 24/7, e riprendi da dove hai lasciato sul web o nell'app.

Corsi
39
Lezioni
144

Domande Frequenti

La lezione «Integrazione con i database (SQLx/Diesel)» è gratuita?

Sì — il testo completo di «Integrazione con i database (SQLx/Diesel)» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso Learn Rust Coding, passa a CoddyKit PRO. Il corso Learn Rust Coding include 3 lezioni in totale.

Cosa imparerò in «Integrazione con i database (SQLx/Diesel)»?

Integri il Suo servizio web Rust con i database utilizzando ORM o query builder diffusi come SQLx o Diesel. Eserciti Learn Rust Coding con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.

Ho bisogno di esperienza per iniziare Learn Rust Coding?

Non è richiesta alcuna esperienza precedente. Learn Rust Coding su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 2 di 3.

Quanto tempo richiede la lezione «Integrazione con i database (SQLx/Diesel)»?

La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.

Posso scrivere ed eseguire codice in questa lezione Learn Rust Coding?

Sì. Ogni lezione Learn Rust Coding include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.

Tutte le lezioni di questo corso

  1. API REST con Actix-web/Rocket
  2. Integrazione con i database (SQLx/Diesel)
  3. Autenticazione e autorizzazione
← Torna a Learn Rust Coding