Rust und SQLx 2026: Compile-Time geprüfte Queries und Interview-Fragen
Ein umfassender Leitfaden zu SQLx 0.9 in Rust mit Compile-Time Query-Validierung, der neuen sqlx.toml Konfiguration und praxisrelevanten Interview-Fragen für Rust-Entwickler.

SQLx 0.9 verändert die Datenbankarbeit in Rust grundlegend, indem SQL-Fehler zur Compile-Zeit statt zur Laufzeit erkannt werden. Die im Mai 2026 veröffentlichte Version führt ein neues Konfigurationssystem, Runtime-Flexibilität und strengere Query-Sicherheit durch das SqlSafeStr-Trait ein.
Im Gegensatz zu ORMs, die SQL aus Rust-Structs generieren, verifiziert SQLx handgeschriebenes SQL gegen eine Live-Datenbank während der Kompilierung. Ein Tippfehler im Spaltennamen lässt den Build fehlschlagen, nicht die Produktion.
Compile-Time Query-Validierung in SQLx 0.9
Das query!-Makro prüft jede SQL-Anweisung gegen das Datenbankschema während cargo build. Dadurch werden Tippfehler, Typ-Mismatches und fehlende Spalten erkannt, bevor der Code jemals ausgeführt wird.
use sqlx::{FromRow, PgPool};
#[derive(FromRow)]
pub struct User {
pub id: i32,
pub email: String,
pub created_at: chrono::DateTime<chrono::Utc>,
}
pub async fn get_user_by_email(pool: &PgPool, email: &str) -> Result<Option<User>, sqlx::Error> {
// Compile-Zeit validiert: Spaltennamen, Typen und Rückgabestruktur
sqlx::query_as!(
User,
r#"
SELECT id, email, created_at
FROM users
WHERE email = $1
"#,
email
)
.fetch_optional(pool)
.await
}Das query_as!-Makro mapped Zeilen direkt auf das User-Struct. Falls die users-Tabelle keine created_at-Spalte hat, schlägt die Kompilierung mit einem klaren Fehler fehl, der auf die exakte Zeile verweist.
Das sqlx.toml Konfigurationssystem
SQLx 0.9 führt eine sqlx.toml-Datei ein, die Datenbankkonfiguration, Typ-Overrides und Multi-Datenbank-Setups zentralisiert. Dies ersetzt verstreute Umgebungsvariablen und vereinfacht CI-Pipelines.
# sqlx.toml
[common]
database_url_var = "DATABASE_URL"
[macros]
default_type_override.uuid = "uuid::Uuid"
default_type_override.timestamptz = "chrono::DateTime<chrono::Utc>"
[sqlite]
extensions = ["uuid", "crypto"]Typ-Overrides eliminieren repetitives Casting. Jede UUID-Spalte wird automatisch auf uuid::Uuid gemappt, und jede timestamptz auf chrono::DateTime ohne Per-Query-Annotationen.
SqlSafeStr: SQL-Injection auf Typ-Ebene verhindern
SQLx 0.9 verstärkt die Query-Sicherheit, indem SqlSafeStr für String-Parameter erforderlich ist. Standardmäßig implementiert nur &'static str dieses Trait, wodurch dynamische Strings blockiert werden, die Injection-Payloads enthalten könnten.
use sqlx::{AssertSqlSafe, PgPool};
// Statischer Tabellenname: kompiliert direkt
const TABLE: &str = "products";
pub async fn search_products(
pool: &PgPool,
user_query: &str,
) -> Result<Vec<Product>, sqlx::Error> {
// Sicher: $1 ist ein parametrisierter Wert, kein interpoliertes SQL
sqlx::query_as!(
Product,
r#"SELECT * FROM products WHERE name ILIKE '%' || $1 || '%'"#,
user_query
)
.fetch_all(pool)
.await
}
// Dynamischer Tabellenname aus Config: in AssertSqlSafe wrappen nach Validierung
pub async fn get_from_table(
pool: &PgPool,
table_name: &str,
) -> Result<Vec<Product>, sqlx::Error> {
// Entwickler übernimmt Verantwortung für die Validierung
let safe_table = AssertSqlSafe(table_name);
sqlx::query_as(&format!("SELECT * FROM {}", safe_table))
.fetch_all(pool)
.await
}Das SqlSafeStr-Trait zwingt Entwickler dazu, explizit über Injection-Risiken nachzudenken. Production-Code sollte dynamische Tabellennamen gegen eine Allowlist validieren, bevor AssertSqlSafe verwendet wird.
Runtime-Flexibilität mit dem runtime Feature
SQLx 0.9 entkoppelt die async Runtime-Auswahl von der Crate-Konfiguration. Das neue runtime-Feature ermöglicht es Anwendungen, zwischen Tokio und async-std zu wechseln, ohne SQLx-Dependencies zu ändern.
# Cargo.toml
[dependencies]
sqlx = { version = "0.9", features = ["runtime-tokio", "postgres", "uuid", "chrono"] }
tokio = { version = "1", features = ["full"] }Für Projekte, die async-std verwenden:
[dependencies]
sqlx = { version = "0.9", features = ["runtime-async-std", "postgres"] }
async-std = { version = "1", features = ["attributes"] }Connection Pool Management und Gesundheitsprüfungen
Der Connection Pool in SQLx 0.9 enthält verbesserte Health-Checks und Connection-Lifecycle-Management. Pool-Optionen ermöglichen feinkörnige Kontrolle über Connection-Recycling.
use sqlx::postgres::{PgPoolOptions, PgConnectOptions};
use std::time::Duration;
pub async fn create_pool() -> Result<sqlx::PgPool, sqlx::Error> {
let connect_options = PgConnectOptions::new()
.host("localhost")
.port(5432)
.database("app_db")
.username("app_user")
.password("secure_password");
PgPoolOptions::new()
.max_connections(20)
.min_connections(5)
.acquire_timeout(Duration::from_secs(5))
.idle_timeout(Duration::from_secs(600))
.max_lifetime(Duration::from_secs(1800))
.test_before_acquire(true)
.connect_with(connect_options)
.await
}Die Option test_before_acquire führt einen Ping durch, bevor Connections an den Anwendungscode übergeben werden, wodurch fehlgeschlagene Connections erkannt werden, die von der Datenbank getrennt wurden.
Transaktionen und Savepoints
SQLx bietet typsichere Transaktionen mit automatischem Rollback bei Fehler. Verschachtelte Transaktionen verwenden Savepoints für partielle Rollback-Fähigkeiten.
use sqlx::PgPool;
pub async fn create_order_with_items(
pool: &PgPool,
user_id: i32,
items: Vec<OrderItem>,
) -> Result<i32, sqlx::Error> {
let mut tx = pool.begin().await?;
// Order erstellen
let order_id: i32 = sqlx::query_scalar!(
"INSERT INTO orders (user_id, status) VALUES ($1, 'pending') RETURNING id",
user_id
)
.fetch_one(&mut *tx)
.await?;
// Savepoint für Items
let savepoint = tx.begin().await?;
for item in items {
sqlx::query!(
"INSERT INTO order_items (order_id, product_id, quantity) VALUES ($1, $2, $3)",
order_id,
item.product_id,
item.quantity
)
.execute(&mut *savepoint)
.await?;
}
savepoint.commit().await?;
tx.commit().await?;
Ok(order_id)
}SQLx vs. Diesel vs. SeaORM: Ein Vergleich
Die Wahl des richtigen Datenbank-Tools hängt von den Projektanforderungen ab. Hier ist ein Vergleich der drei führenden Rust-Datenbank-Bibliotheken:
| Eigenschaft | SQLx | Diesel | SeaORM |
|---|---|---|---|
| Query-Stil | Rohes SQL | Query Builder DSL | ActiveRecord-Muster |
| Compile-Zeit-Prüfung | Ja (gegen Live-DB) | Ja (gegen Schema) | Nein |
| Async Support | Native | Via diesel-async | Native |
| Lernkurve | Niedrig (SQL-Kenntnisse) | Mittel (DSL-Lernen) | Niedrig (ORM-vertraut) |
| Migrationen | sqlx-cli | Diesel-CLI | SeaORM-CLI |
SQLx eignet sich am besten für Teams mit starker SQL-Expertise, die maximale Kontrolle über Queries benötigen. Diesel eignet sich für Projekte, die statische Schema-Validierung ohne Datenbankverbindung während des Builds bevorzugen. SeaORM bietet ein vertrautes ORM-Erlebnis für Entwickler, die aus anderen Sprachen kommen.
Bereit für deine Rust-Interviews?
Übe mit unseren interaktiven Simulatoren, Flashcards und technischen Tests.
Interview-Fragen zu Rust und SQLx
Die folgenden Fragen werden häufig in technischen Interviews für Rust-Backend-Positionen gestellt:
Wie funktioniert die Compile-Zeit-Validierung von SQLx?
SQLx verbindet sich während cargo build mit einer echten Datenbank und validiert jeden query!-Aufruf gegen das Live-Schema. Der Compiler speichert Query-Metadaten in einer .sqlx-Datei zwischen, die für Offline-Kompilierung eingecheckt werden kann. Diese Validierung prüft Spaltennamen, Parametertypen und Rückgabestrukturen.
Was ist der Unterschied zwischen query! und query_as!?
Das query!-Makro gibt einen anonymen Record-Typ mit benannten Feldern zurück, auf die via .field_name zugegriffen werden kann. Das query_as!-Makro mapped Ergebnisse auf ein benutzerdefiniertes Struct, das FromRow implementiert. Letzteres ist vorzuziehen, wenn Query-Ergebnisse innerhalb einer Anwendung weitergegeben werden.
Wie werden NULL-Werte in SQLx behandelt?
Spalten, die nullable sind, werden auf Option<T> in Rust gemappt. SQLx leitet Nullability aus dem Datenbankschema ab. Für Queries, die die Compile-Zeit-Validierung umgehen, kann das Attribut #[sqlx(default)] Standardwerte für fehlende Spalten bereitstellen.
Erkläre Connection Pooling in SQLx
SQLx verwendet einen async-fähigen Connection Pool, der Connections über mehrere Tasks hinweg wiederverwendet. Der Pool erhält eine minimale Anzahl von Idle-Connections aufrecht und erstellt neue bis zur konfigurierten maximalen Anzahl. Connections werden Health-geprüft, bevor sie an die Anwendung geliefert werden, und nach Überschreitung der maximalen Lebensdauer recycelt.
Wie verhindert SqlSafeStr SQL-Injection?
Das SqlSafeStr-Trait markiert Strings, die sicher für SQL-Interpolation sind. Standardmäßig implementieren nur statische String-Literale dieses Trait. Dynamische Strings erfordern explizites Wrapping mit AssertSqlSafe, was Entwickler zwingt, über Injection-Risiken nachzudenken und Input vor der Verwendung zu validieren.
Wann sollte man SQLx statt Diesel verwenden?
SQLx ist vorzuziehen, wenn komplexe Queries lesbares SQL erfordern, wenn das Team starke SQL-Kenntnisse hat, oder wenn die async Runtime-Kompatibilität kritisch ist. Diesel ist besser geeignet, wenn eine Compile-Zeit-Schema-Validierung ohne Datenbankverbindung benötigt wird oder wenn eine typsichere Query-Builder-API bevorzugt wird.
Migrationen mit sqlx-cli
Das sqlx-cli-Tool verwaltet Datenbankmigrationen und Schema-Synchronisation. Migrationen werden als SQL-Dateien mit Versionspräfixen gespeichert.
# sqlx-cli installieren
cargo install sqlx-cli --features postgres
# Neue Migration erstellen
sqlx migrate add create_users_table
# Migrationen ausführen
sqlx migrate run
# Letzte Migration rückgängig machen
sqlx migrate revertEine Migration besteht aus zwei Dateien:
-- migrations/20260912000000_create_users_table.up.sql
CREATE TABLE users (
id SERIAL PRIMARY KEY,
email VARCHAR(255) NOT NULL UNIQUE,
password_hash VARCHAR(255) NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_users_email ON users(email);-- migrations/20260912000000_create_users_table.down.sql
DROP TABLE IF EXISTS users;Offline-Modus für CI/CD
Für CI-Umgebungen ohne Datenbankzugriff generiert SQLx Metadaten-Dateien, die eingecheckt werden können:
# Query-Metadaten generieren
cargo sqlx prepare
# .sqlx-Verzeichnis in Git committen
git add .sqlx
git commit -m "Update SQLx query metadata"Die CI-Pipeline kann dann ohne Datenbankverbindung kompilieren, indem die Metadaten-Dateien verwendet werden.
Fazit
SQLx 0.9 stellt einen bedeutenden Fortschritt für typsichere Datenbankinteraktionen in Rust dar. Die Compile-Zeit-Query-Validierung fängt Fehler früh ab, das neue Konfigurationssystem vereinfacht Multi-Datenbank-Setups, und das SqlSafeStr-Trait fügt eine zusätzliche Sicherheitsebene gegen SQL-Injection hinzu. Für Entwickler, die sich auf Rust-Backend-Interviews vorbereiten, ist das Verständnis dieser Konzepte entscheidend, da SQLx zur Standard-Wahl für asynchronen Datenbankzugriff in der Rust-Ökosystem geworden ist.
Findest du den Bug in Rust?
Ein echter Codeausschnitt, ein versteckter Bug, ein Versuch pro Tag. Zum Ausprobieren ohne Konto.

Geschrieben von
Anthony Fillion-MailletGründer von SharpSkill
Seit über 10 Jahren Fullstack-Entwickler. Er leitet SharpSkill und verantwortet alles, was hier erscheint.
Aktualisiert am 12. September 2026
Tags
Teilen
Verwandte Artikel

Rust Lifetimes verstehen: Annotationen, Elision und Interview-Fragen 2026
Ein umfassender Leitfaden zu Rust Lifetimes: von grundlegenden Konzepten über Lifetime-Annotationen bis hin zu Elision-Regeln und häufigen Interview-Fragen für Rust-Entwickler.

Rust Smart Pointer erklärt: Box, Rc, Arc und RefCell im Jahr 2026
Rust Smart Pointer Box, Rc, Arc und RefCell erklärt mit kompilierbaren 2026-Beispielen, einer Entscheidungstabelle und häufigen Interviewfragen.

Rust Traits und Generics 2026: Trait Upcasting, AsyncFn und fortgeschrittene Patterns
Rust Traits und Generics mit den Features der 2024 Edition: Trait Upcasting, AsyncFn-Closures, RPITIT und fortgeschrittene Patterns. Mit Interview-Fragen und kompilierbarem Code.