Database-integratie
Data persistent maken
Database-integratie is een gratis Leer programmeren met Rust-les op CoddyKit. Dit is les 3 van 4. Je kunt 3 lessen uit dit leerpad gratis volledig lezen — daarna ontgrendelt CoddyKit PRO alle lessen, plus praktische oefeningen met een ingebouwde code-editor en een AI-tutor die 24/7 beschikbaar is. Deze les maakt deel uit van het leertraject Leer programmeren met Rust. Je voortgang wordt gesynchroniseerd op het web en in de CoddyKit-app. De cursus Leer programmeren met Rust bevat in totaal 4 lessen.
Gegevens persistent opslaan
Tot nu toe sloeg onze API gegevens in het geheugen op, waardoor deze bij een herstart verdwijnen. Echte services hebben een database nodig. In deze les verbinden we een Axum-API met PostgreSQL via sqlx, een asynchrone SQL-toolkit voor Rust met compileertijdcontroles.
Je leert connectionpools, queries, rijen aan structs koppelen en de pool als gedeelde status gebruiken.
sqlx toevoegen
Voeg sqlx toe met de functies die je nodig hebt: een runtime, TLS en een databasestuurprogramma. Hieronder staat een Postgres-configuratie met Tokio.
// Cargo.toml
// [dependencies]
// sqlx = { version = "0.7", features = [
// "runtime-tokio", "tls-rustls", "postgres", "macros"
// ] }De connectionpool
Voor elk request een nieuwe verbinding openen is traag. Een connectionpool houdt een verzameling herbruikbare verbindingen bij. PgPoolOptions bouwt er een op basis van een database-URL. De pool is goedkoop te klonen (intern gebruikt deze referentietelling), waardoor hij ideaal is als gedeelde status.
use sqlx::postgres::PgPoolOptions;
async fn make_pool(url: &str) -> sqlx::PgPool {
PgPoolOptions::new()
.max_connections(5)
.connect(url)
.await
.expect("failed to connect")
}De pool als applicatiestatus
Geef de pool met .with_state(pool) door aan Axum. Handlers nemen vervolgens State(pool): State<PgPool> aan. Omdat de pool goedkoop kan worden gekloond, deelt elk request dezelfde onderliggende verbindingen.
use axum::{routing::get, Router};
use sqlx::PgPool;
fn build(pool: PgPool) -> Router {
Router::new()
.route("/todos", get(list_todos))
.with_state(pool)
}Een query uitvoeren
De functie sqlx::query voert ruwe SQL uit. Bind parameters met .bind(value) om SQL-injectie te voorkomen; Postgres gebruikt $1- en $2-plaatshouders. Gebruik .execute(&pool) voor schrijfbewerkingen die geen rijen retourneren.
use sqlx::PgPool;
async fn insert_todo(pool: &PgPool, title: &str) -> Result<(), sqlx::Error> {
sqlx::query("INSERT INTO todos (title, done) VALUES ($1, $2)")
.bind(title)
.bind(false)
.execute(pool)
.await?;
Ok(())
}Rijen aan structs koppelen
Leid sqlx::FromRow af voor je model, zodat queryresultaten er rechtstreeks aan kunnen worden gekoppeld. Gebruik query_as::<_, Todo> met fetch_all om een Vec<Todo> te krijgen, of fetch_one voor één rij.
use sqlx::{PgPool, FromRow};
#[derive(FromRow, serde::Serialize)]
struct Todo { id: i32, title: String, done: bool }
async fn all_todos(pool: &PgPool) -> Result<Vec<Todo>, sqlx::Error> {
let rows = sqlx::query_as::<_, Todo>("SELECT id, title, done FROM todos")
.fetch_all(pool)
.await?;
Ok(rows)
}Een handler die de database leest
Breng de onderdelen samen: een handler haalt de pool uit de status, voert een query uit en retourneert JSON. Koppel databasefouten aan status 500, zodat de client een nette response krijgt in plaats van een panic.
use axum::{extract::State, Json, http::StatusCode};
use sqlx::PgPool;
async fn list_todos(
State(pool): State<PgPool>,
) -> Result<Json<Vec<Todo>>, StatusCode> {
match all_todos(&pool).await {
Ok(todos) => Ok(Json(todos)),
Err(_) => Err(StatusCode::INTERNAL_SERVER_ERROR),
}
}Ingevoegde rijen retourneren
Postgres kan de rij die zojuist is ingevoegd retourneren met RETURNING. Combineer dit met query_as en fetch_one om het nieuwe record, inclusief de gegenereerde id, in één heen-en-terugbewerking op te halen.
use sqlx::PgPool;
async fn create(pool: &PgPool, title: &str) -> Result<Todo, sqlx::Error> {
let todo = sqlx::query_as::<_, Todo>(
"INSERT INTO todos (title, done) VALUES ($1, false) \
RETURNING id, title, done")
.bind(title)
.fetch_one(pool)
.await?;
Ok(todo)
}Migraties
Je schema moet bestaan voordat queries kunnen worden uitgevoerd. sqlx ondersteunt migraties: SQL-bestanden in een map migrations/ die op volgorde worden toegepast. Voer ze bij het opstarten uit met sqlx::migrate!(), zodat een lege database automatisch wordt ingesteld.
use sqlx::PgPool;
async fn run_migrations(pool: &PgPool) {
sqlx::migrate!("./migrations")
.run(pool)
.await
.expect("migrations failed");
}
// migrations/0001_init.sql contains the CREATE TABLE statements.Transacties
Wanneer meerdere schrijfbewerkingen samen moeten slagen, wikkel je ze in een transactie. Begin met pool.begin(), voer queries uit op de transactionele handle en voer daarna commit uit. Als je de transactie verwijdert zonder deze te bevestigen, draait sqlx haar automatisch terug, zodat de gegevens consistent blijven.
use sqlx::PgPool;
async fn transfer(pool: &PgPool) -> Result<(), sqlx::Error> {
let mut tx = pool.begin().await?;
sqlx::query("UPDATE accounts SET balance = balance - 10 WHERE id = 1")
.execute(&mut *tx).await?;
sqlx::query("UPDATE accounts SET balance = balance + 10 WHERE id = 2")
.execute(&mut *tx).await?;
tx.commit().await?;
Ok(())
}Configuratie en geheimen
Hardcode nooit databasegegevens. Lees DATABASE_URL uit de omgeving; tijdens de ontwikkeling wordt deze vaak uit een .env-bestand geladen met de crate dotenvy. In productie injecteert het platform deze als omgevingsvariabele.
use std::env;
async fn connect_from_env() -> sqlx::PgPool {
let url = env::var("DATABASE_URL")
.expect("DATABASE_URL must be set");
make_pool(&url).await
}Korte controle
Test je begrip van database-integratie.
Samenvatting
Je hebt een database geïntegreerd:
- Gebruik een verbindingspool van het type
PgPoolen deel deze via.with_state. - Gebruik
query/executevoor schrijfbewerkingen enquery_asmetFromRowvoor getypeerde leesbewerkingen. - Bind parameters altijd om SQL-injectie te voorkomen.
- Met
RETURNINGhaal je ingevoegde rijen op; transacties groeperen schrijfbewerkingen atomair. - Voer migraties uit bij het opstarten en lees
DATABASE_URLuit de omgeving.
Leer Rust met een AI-tutor — gratis
Schrijf echte code en voer die uit in je browser, krijg direct hulp van een AI-tutor die 24/7 beschikbaar is en ga verder waar je gebleven bent op het web of in de app.
- Cursussen
- 39
- Lessen
- 144
Veelgestelde vragen
Is de les “Database-integratie” gratis?
Ja — je kunt hier op het web alle 3 lessen van het leerpad Leer programmeren met Rust, waaronder “Database-integratie”, gratis volledig lezen. Daarna ontgrendelt CoddyKit PRO alle lessen, plus interactieve oefeningen met een ingebouwde code-editor en een AI-tutor die 24/7 beschikbaar is. De cursus Leer programmeren met Rust bevat in totaal 4 lessen.
Wat leer ik in “Database-integratie”?
Data persistent maken Je oefent met Leer programmeren met Rust door code rechtstreeks in de browser uit te voeren. Een AI-begeleider die 24/7 beschikbaar is beantwoordt je vragen terwijl je de les doorwerkt.
Heb ik ervaring nodig om met Leer programmeren met Rust te beginnen?
Ervaring vooraf is niet nodig. Leer programmeren met Rust op CoddyKit is opgebouwd voor beginners tot gevorderden, zodat je hier of bij het begin kunt starten en in je eigen tempo kunt leren. Dit is les 3 van 4.
Hoe lang duurt de les “Database-integratie”?
De meeste lessen van CoddyKit duren ongeveer 5–10 minuten. Elke les is kort en interactief, zodat je gestaag vooruitgaat en op het web en in de app precies verdergaat waar je was gebleven.
Kan ik code schrijven en uitvoeren in deze les over Leer programmeren met Rust?
Ja. Elke les over Leer programmeren met Rust bevat een ingebouwde code-editor, zodat je rechtstreeks in je browser echte code kunt schrijven en uitvoeren en direct feedback van AI krijgt — lokale installatie is niet nodig.
Alle lessen in deze cursus
- Projectconfiguratie
- Endpoints en modellen
- Database-integratie
- De API testen