SQLx für Rust: Vollständiges Tutorial mit Beispielen

Online Python-Trainer für Anfänger

Lernen Sie Python einfach ohne theoretische Überlastung. Lösen Sie praktische Aufgaben mit automatischer Überprüfung und schreiben Sie Code direkt im Browser.

Kurs starten

Was ist SQLx und warum wird es benötigt?

SQLx ist eine asynchrene, reine Rust-Bibliothek für die Arbeit mit Datenbanken, die den Ansatz "SQL ohne ORM" umsetzt. Im Gegensatz zu ORM-Lösungen wie Diesel oder SeaORM verbirgt SQLx keine SQL-Abfragen hinter Abstraktionen, sondern ermöglicht es, reinen SQL-Code zu schreiben, während es gleichzeitig vollständige Typsicherheit zur Kompilierungszeit gewährleistet.

Die wichtigsten Vorteile von SQLx:

  • Typsicherheit zur Kompilierungszeit — SQLx überprüft Ihre SQL-Abfragen während des Builds auf Übereinstimmung mit dem Datenbankschema.
  • Asynchronität von Haus aus — Die Bibliothek unterstützt vollständig async/await, ideal für hochbelastete Webanwendungen.
  • Unterstützung mehrerer DBMS — PostgreSQL, MySQL, SQLite und MSSQL.
  • Keine Magie — Sie schreiben normales SQL, die Bibliothek hilft nur beim sicheren Übergeben von Parametern und Abrufen von Ergebnissen.
  • Migrationen — Integriertes System zur Verwaltung von Datenbankschema-Migrationen.

SQLx ist ideal für Projekte, bei denen vollständige Kontrolle über Abfragen, Leistung und Typsicherheit wichtig sind, aber man keine komplexen DSLs (domänenspezifische Sprachen) von ORMs erlernen möchte.

Installation

SQLx wird über den Paketmanager Cargo installiert. Fügen Sie die Abhängigkeit in Ihre Cargo.toml-Datei ein:

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

Wählen Sie je nach verwendeter Datenbank das entsprechende Feature-Flag:

  • postgres — für PostgreSQL
  • mysql — für MySQL
  • sqlite — für SQLite
  • mssql — für Microsoft SQL Server

Für die Runtime können Sie runtime-tokio-rustls (empfohlen) oder runtime-async-std-rustls wählen.

Schnellstart

Erstellen wir eine einfache Anwendung, die eine Verbindung zu PostgreSQL herstellt und eine Abfrage ausführt:

use sqlx::postgres::PgPoolOptions;
use anyhow::Result;

#[tokio::main]
async fn main() -> Result<()> {
    // Verbindungspool erstellen
    let pool = PgPoolOptions::new()
        .max_connections(5)
        .connect("postgres://user:password@localhost/mydb")
        .await?;

    // Einfache Abfrage ausführen
    let row: (i64,) = sqlx::query_as("SELECT $1::bigint")
        .bind(42_i64)
        .fetch_one(&pool)
        .await?;

    println!("Ergebnis: {}", row.0);

    Ok(())
}

Dieser Code erstellt einen Pool mit 5 Verbindungen zur Datenbank, führt eine Abfrage mit einem Parameter aus und gibt das Ergebnis aus.

Wichtige Methoden und Funktionen von SQLx

1. sqlx::query

Funktion: Erstellt eine neue SQL-Abfrage mit der Möglichkeit, Parameter zu binden. Dies ist der grundlegende Baustein für alle Operationen.

Parameter:

  • sql: &str — SQL-Abfragezeichenfolge mit Platzhaltern ($1, $2 für PostgreSQL; ? für MySQL/SQLite)

Beispiel:

use sqlx::query;

let query = sqlx::query("SELECT * FROM users WHERE id = $1 AND active = $2")
    .bind(1)
    .bind(true);

2. .bind()

Funktion: Bindet einen Wert an einen Abfrageparameter. Die Reihenfolge der Aufrufe entspricht der Reihenfolge der Platzhalter im SQL.

Parameter:

  • value: impl Encode + Type<DB> — jeder Wert, der für die Datenbank kodiert werden kann (i32, String, bool, Option usw.)

Beispiel:

let user_id: i32 = 42;
let user_name: &str = "Alice";

sqlx::query("INSERT INTO users (id, name) VALUES ($1, $2)")
    .bind(user_id)
    .bind(user_name)
    .execute(&pool)
    .await?;

3. .fetch_one()

Funktion: Führt die Abfrage aus und gibt genau eine Zeile zurück. Wenn keine oder mehr als eine Zeile vorhanden sind, wird ein Fehler ausgelöst.

Parameter:

  • executor: impl Executor<'_> — Datenbankverbindung oder Pool

Beispiel:

let row: (i32, String) = sqlx::query_as("SELECT id, name FROM users WHERE id = $1")
    .bind(1)
    .fetch_one(&pool)
    .await?;

println!("ID: {}, Name: {}", row.0, row.1);

Empfehlungen