Rust-ohjelmoinnin perusteet · Oppitunti

Tietokantaintegraatio

Säilyttäkää data.

Oppitunti 3/413 vaihetta

Tietokantaintegraatio on ilmainen Rust-ohjelmoinnin perusteet-oppitunti CoddyKitissä. Tämä on oppitunti 3/4. Voit lukea tästä oppimispolusta kokonaan mitkä tahansa 3 oppituntia ilmaiseksi — sen jälkeen CoddyKit PRO avaa kaikki oppitunnit sekä käytännön harjoittelun sisäänrakennetulla koodieditorilla ja ympäri vuorokauden toimivalla tekoälytuutorilla. Oppitunti kuuluu Rust-ohjelmoinnin perusteet-oppimispolkuun, ja edistymisesi synkronoituu verkon ja CoddyKit-sovelluksen välillä. Rust-ohjelmoinnin perusteet-kurssilla on yhteensä 4 oppituntia.

Datan pysyväistallennus

Tähän asti rajapintamme on tallentanut datan muistiin, joten se katoaa uudelleenkäynnistyksen yhteydessä. Oikeat palvelut tarvitsevat tietokannan. Tällä oppitunnilla yhdistämme Axum-rajapinnan PostgreSQL:ään käyttämällä sqlx:ää, joka on Rustin asynkroninen ja käännösaikana tarkistettava SQL-työkalupakki.

Opitte yhteyspoolit, kyselyt, rivien yhdistämisen rakenteisiin ja poolin käyttämisen jaettuna tilana.

sqlx:n lisääminen

Lisätkää sqlx tarvitsemillanne ominaisuuksilla: suoritusympäristö, TLS ja tietokanta-ajuri. Alla on Postgres-määritys, joka käyttää Tokiota.

// Cargo.toml
// [dependencies]
// sqlx = { version = "0.7", features = [
//   "runtime-tokio", "tls-rustls", "postgres", "macros"
// ] }

Yhteyspooli

Uuden yhteyden avaaminen jokaista pyyntöä varten on hidasta. Yhteyspooli ylläpitää joukkoa uudelleenkäytettäviä yhteyksiä. PgPoolOptions rakentaa poolin tietokannan URL-osoitteesta. Poolin kloonaaminen on edullista (sen sisäinen toteutus käyttää viitelaskentaa), joten se sopii erinomaisesti jaetuksi tilaksi.

use sqlx::postgres::PgPoolOptions;

async fn make_pool(url: &str) -> sqlx::PgPool {
    PgPoolOptions::new()
        .max_connections(5)
        .connect(url)
        .await
        .expect("failed to connect")
}

Pooli sovellustilana

Välittäkää pooli Axumille komennolla .with_state(pool). Käsittelijät vastaanottavat sen muodossa State(pool): State<PgPool>. Koska poolin kloonaaminen on edullista, kaikki pyynnöt jakavat samat taustalla olevat yhteydet.

use axum::{routing::get, Router};
use sqlx::PgPool;

fn build(pool: PgPool) -> Router {
    Router::new()
        .route("/todos", get(list_todos))
        .with_state(pool)
}

Kyselyn suorittaminen

sqlx::query-funktio suorittaa raakaa SQL:ää. Sitokaa parametrit .bind(value)-kutsulla SQL-injektioiden välttämiseksi; Postgres käyttää paikanhaltijoita $1 ja $2. Käyttäkää kirjoitusoperaatioihin, jotka eivät palauta rivejä, komentoa .execute(&pool).

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(())
}

Rivien yhdistäminen rakenteisiin

Johtakaa mallillenne sqlx::FromRow, jotta kyselytulokset yhdistyvät siihen suoraan. Käyttäkää query_as::<_, Todo>-funktiota yhdessä fetch_all-kutsun kanssa saadaksenne Vec<Todo>-arvon tai käyttäkää fetch_one-kutsua yksittäiselle riville.

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)
}

Tietokannasta lukeva käsittelijä

Yhdistäkää osat: käsittelijä vastaanottaa poolin tilasta, suorittaa kyselyn ja palauttaa JSON-dataa. Muuntakaa tietokantavirheet 500-tilakoodiksi, jotta asiakas saa siistin vastauksen paniikin sijaan.

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),
    }
}

Lisättyjen rivien palauttaminen

Postgres voi palauttaa juuri lisäämänsä rivin RETURNING-lauseella. Yhdistäkää se query_as- ja fetch_one-kutsuihin saadaksenne uuden tietueen, mukaan lukien sen luodun tunnisteen, yhdellä edestakaisella kyselyllä.

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)
}

Migraatiot

Kaavion on oltava olemassa ennen kyselyiden suorittamista. sqlx tukee migraatioita: migrations/-kansiossa olevia SQL-tiedostoja, jotka otetaan käyttöön järjestyksessä. Suorittakaa ne käynnistyksen yhteydessä komennolla sqlx::migrate!(), jotta uusi tietokanta määritetään automaattisesti.

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.

Transaktiot

Kun useiden kirjoitusoperaatioiden on onnistuttava yhdessä, kääritkää ne transaktioon. Aloittakaa komennolla pool.begin(), suorittakaa kyselyt transaktion käsittelijää käyttäen ja kutsukaa lopuksi commit. Jos transaktio pudotetaan ilman vahvistamista, sqlx peruuttaa sen automaattisesti ja pitää datan yhdenmukaisena.

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(())
}

Asetukset ja salaisuudet

Älkää koskaan kovakoodatko tietokannan tunnistetietoja. Lukekaa DATABASE_URL ympäristöstä. Kehityksen aikana se ladataan usein .env-tiedostosta dotenvy-craten avulla. Tuotannossa alusta välittää sen ympäristömuuttujana.

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
}

Pikatarkistus

Testatkaa, miten hyvin ymmärrätte tietokantaintegraation.

Kertaus

Integroitte tietokannan:

  • Käyttäkää PgPool-yhteyspoolia ja jakakaa se .with_state-metodin avulla.
  • Käyttäkää kirjoituksiin query/execute-metodeja ja tyypitettyihin lukuihin query_as-metodia yhdessä FromRow-piirteen kanssa.
  • Sitokaa parametrit aina SQL-injektioiden estämiseksi.
  • RETURNING hakee lisätyt rivit, ja transaktiot ryhmittelevät kirjoitukset atomisesti.
  • Suorittakaa migraatiot käynnistyksen yhteydessä ja lukekaa DATABASE_URL ympäristöstä.
Aloita maksutta

Opi Rust tekoälytuutorin avulla — ilmaiseksi

Kirjoita ja suorita oikeaa koodia selaimessa, saa välitöntä apua tekoälytuutorilta ympäri vuorokauden ja jatka siitä, mihin jäit, verkossa tai sovelluksessa.

Kurssit
39
Oppitunnit
144

Usein kysytyt kysymykset

Onko oppitunti ”Tietokantaintegraatio” ilmainen?

Kyllä — voit lukea täällä verkossa kokonaan ilmaiseksi mitkä tahansa Rust-ohjelmoinnin perusteet-oppimispolun 3 oppituntia, myös oppitunnin “Tietokantaintegraatio”. Sen jälkeen CoddyKit PRO avaa kaikki oppitunnit sekä interaktiiviset harjoitukset sisäänrakennetulla koodieditorilla ja ympäri vuorokauden toimivalla tekoälytuutorilla. Rust-ohjelmoinnin perusteet-kurssilla on yhteensä 4 oppituntia.

Mitä opin oppitunnilla ”Tietokantaintegraatio”?

Säilyttäkää data. Harjoittelet Rust-ohjelmoinnin perusteet-aihetta koodilla, jonka suoritat suoraan selaimessa. Ympäri vuorokauden käytettävissä oleva tekoälytuutori vastaa kysymyksiisi oppitunnin aikana.

Tarvitsenko kokemusta aloittaakseni Rust-ohjelmoinnin perusteet-opiskelun?

Aiempi kokemus ei ole tarpeen. CoddyKitin Rust-ohjelmoinnin perusteet-oppimispolku sopii vasta-alkajista edistyneisiin, joten voit aloittaa tästä tai alusta ja edetä omaan tahtiisi. Tämä on oppitunti 3/4.

Kuinka kauan ”Tietokantaintegraatio”-oppitunnin suorittaminen kestää?

Useimmat CoddyKitin oppitunnit kestävät noin 5–10 minuuttia. Jokainen oppitunti on lyhyt ja interaktiivinen, joten edistyt tasaisesti ja voit jatkaa siitä, mihin jäit – sekä verkossa että sovelluksessa.

Voinko kirjoittaa ja suorittaa koodia tällä Rust-ohjelmoinnin perusteet-oppitunnilla?

Kyllä. Jokainen Rust-ohjelmoinnin perusteet-oppitunti sisältää sisäänrakennetun koodieditorin, joten voit kirjoittaa ja suorittaa oikeaa koodia suoraan selaimessa ja saada välitöntä palautetta tekoälyltä – paikallista asennusta ei tarvita.

Kaikki tämän kurssin oppitunnit

  1. Projektin määritys
  2. Päätepisteet ja mallit
  3. Tietokantaintegraatio
  4. APIn testaaminen
← Takaisin: Rust-ohjelmoinnin perusteet