ORM für Rust: vollständiger Vergleich und Anwendungsbeispiele
Das Rust-Ökosystem bietet mehrere leistungsstarke Lösungen für die Arbeit mit Datenbanken. In diesem Artikel vergleichen wir drei Hauptansätze im Detail: Diesel (synchroner, kompilierbarer ORM), SeaORM (asynchron, flexibel) und SQLx (minimalistisch, mit Abfrageprüfung zur Kompilierzeit). Sie erfahren, welches Tool Sie für bestimmte Aufgaben wählen sollten, und sehen funktionierende Codebeispiele.
1. Diesel – bewährter synchroner ORM
Diesel ist der ausgereifteste ORM für Rust. Sein Hauptmerkmal ist die Typsicherheit zur Kompilierzeit. Alle SQL-Abfragen werden während des Builds überprüft, was eine ganze Klasse von Fehlern ausschließt. Funktioniert nur synchron, aber mit tokio kann ein Verbindungspool organisiert werden.
Beispiel für die Verwendung von Diesel:
// models.rs#[derive(Queryable, Insertable)]#[table_name = "users"]pub struct User { pub id: i32, pub name: String, pub email: String,}
// main.rsuse diesel::prelude::*;use diesel::dsl::insert_into;
fn main() { let conn = PgConnection::establish("postgres://user:pass@localhost/db") .expect("Database connection failed");
let new_user = User { id: 0, name: "Alice".into(), email: "alice@example.com".into(), };
let inserted = insert_into(users::table) .values(&new_user) .get_result::<User>(&conn) .expect("Insert failed");
println!("Created user: {}", inserted.name);}Vorteile: maximale Leistung, strenge Typisierung, integrierte Migrationen.
Nachteile: synchron, komplexe Einrichtung, unterstützt async nicht von Haus aus.
2. SeaORM – asynchron und flexibel
SeaORM ist ein moderner asynchroner ORM, der auf sqlx aufbaut. Unterstützt tokio und async-std. Bietet eine umfangreiche API für CRUD, Beziehungen (eins-zu-eins, eins-zu-viele) und Migrationen. Ideal für Webanwendungen mit Actix oder Axum.
Beispiel mit SeaORM:
use sea_orm::*;use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel)]#[sea_orm(table_name = "users")]pub struct Model { #[sea_orm(primary_key)] pub id: i32, pub name: String, pub email: String,}
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]pub enum Relation {}
impl ActiveModelBehavior for ActiveModel {}
// Verwendungasync fn create_user(db: &DatabaseConnection) -> Result<(), DbErr> { let user = ActiveModel { name: Set("Bob".to_owned()), email: Set("bob@example.com".to_owned()), ..Default::default() }; let result = user.insert(db).await?; println!("User created with id: {}", result.id); Ok(())}Vorteile: vollwertiges async, Unterstützung für PostgreSQL, MySQL, SQLite, einfache Migrationen.
Nachteile: langsamer als Diesel in synthetischen Tests, mehr Abhängigkeiten.
3. SQLx – leichtgewichtig und sicher
SQLx ist kein ORM im klassischen Sinne, sondern ein asynchroner SQL-Treiber mit Abfrageprüfung zur Kompilierzeit. Sie schreiben reines SQL, und SQLx überprüft dessen Syntax und Argumenttypen. Unterstützt PostgreSQL, MySQL, SQLite. Eine ausgezeichnete Wahl, wenn Sie die volle Kontrolle über Abfragen bevorzugen.
Beispiel SQLx:
use sqlx::postgres::PgPool;
#[derive(sqlx::FromRow)]struct User { id: i32, name: String, email: String,}
#[tokio::main]async fn main() -> Result<(), sqlx::Error> { let pool = PgPool::connect("postgres://user:pass@localhost/db").await?;
let user = sqlx::query_as::<_, User>( "SELECT id, name, email FROM users WHERE email = $1"