Arbeiten mit Datenbanken in Rust: PostgreSQL und MongoDB in der Praxis

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

Einleitung: Warum Rust und Datenbanken eine starke Kombination sind

Rust ist eine systemnahe Programmiersprache, die die Leistung von C/C++ mit Speichersicherheit kombiniert. Lange Zeit galt das Ökosystem für die Arbeit mit Datenbanken in Rust jedoch als "unausgereift". Heute hat sich die Situation grundlegend geändert: Die Bibliotheken sqlx (für PostgreSQL) und der offizielle Treiber mongodb bieten ausgereifte, asynchrone und sichere APIs.

In diesem Artikel werden wir praktisch erarbeiten, wie man von Rust aus eine Verbindung zu PostgreSQL und MongoDB herstellt, CRUD-Operationen durchführt und Fehler behandelt. Alle Beispiele verwenden die asynchrone Laufzeitumgebung tokio.



1. Projekteinrichtung und Installation der Abhängigkeiten

Erstellen Sie ein neues Cargo-Projekt:

cargo new rust_db_examplecd rust_db_example

Fügen Sie die folgenden Abhängigkeiten in Cargo.toml hinzu:

[dependencies]tokio = { version = "1", features = ["full"] }sqlx = { version = "0.7", features = ["runtime-tokio-rustls", "postgres"] }mongodb = "2.8"serde = { version = "1", features = ["derive"] }anyhow = "1"
  • sqlx — asynchroner Treiber für PostgreSQL mit Abfrageprüfung zur Kompilierzeit.
  • mongodb — offizieller Treiber von MongoDB Inc.
  • serde — zur Serialisierung/Deserialisierung von Strukturen.
  • anyhow — für komfortable Fehlerbehandlung.


2. Arbeiten mit PostgreSQL über sqlx

2.1 Verbindung zur Datenbank herstellen

Für die Verbindung verwenden Sie einen Verbindungsstring (connection string) der Form postgres://user:password@localhost/dbname. Beispiel:

use sqlx::postgres::PgPool;use anyhow::Result;

#[tokio::main]async fn main() -> Result<()> { let pool = PgPool::connect("postgres://postgres:password@localhost/testdb").await?; println!("Verbindung zu PostgreSQL hergestellt!"); Ok(())}


2.2 Tabelle erstellen und Daten einfügen

Definieren wir die Struktur User und führen eine Migration durch:

use serde::{Deserialize, Serialize};use sqlx::FromRow;

#[derive(Debug, Serialize, Deserialize, FromRow)]struct User { id: i32, name: String, email: String,}

async fn create_table(pool: &PgPool) -> Result<()> { sqlx::query( "CREATE TABLE IF NOT EXISTS users ( id SERIAL PRIMARY KEY, name VARCHAR(255) NOT NULL, email VARCHAR(255) NOT NULL UNIQUE )" ) .execute(pool) .await?; println!("Tabelle users erstellt"); Ok(())}

async fn insert_user(pool: &PgPool, name: &str, email: &str) -> Result<User> { let user = sqlx::query_as::<_, User>( "INSERT INTO users (name, email) VALUES ($1, $2) RETURNING id, name, email" ) .bind(name) .bind(email) .fetch_one(pool) .await?; Ok(user)}

Beachten Sie $1, $2 — dies sind parametrisierte Abfragen, die vor SQL-Injection schützen.



2.3 Daten lesen und aktualisieren

async fn get_user_by_email(pool: &PgPool, email: &str) -> Result<Option<User>> {    let user = sqlx::query_as::<_, User>("SELECT * FROM users WHERE email = $1")        .bind(email)        .fetch_optional(pool)        .await?;    Ok(user)}

async fn update_user_name(pool: &PgPool, id: i32, new_name: &str) -> Result<()> { sqlx::query("UPDATE users SET name = $1 WHERE id = $2") .bind(new_name) .bind(id) .execute(pool) .await?; println!("Benutzer {} aktualisiert", id); Ok(())}

Die Verwendung von fetch_optional ermöglicht es, den Fall zu behandeln, dass ein Datensatz nicht gefunden wird, ohne eine Panik auszulösen.



3. Arbeiten mit MongoDB über den offiziellen Treiber

3.1 Verbindung herstellen und Datenbank auswählen

Blogs

Buchempfehlungen