0Pricing
Learn Rust Coding · Lekcja

Integracja z bazami danych (SQLx/Diesel)

Zintegrują Państwo usługę webową w Rust z bazami danych za pomocą popularnych ORM-ów lub kreatorów zapytań, takich jak SQLx czy Diesel.

Integracja z bazami danych (SQLx/Diesel) to bezpłatna lekcja Learn Rust Coding na CoddyKit. To lekcja 2 z 3. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Learn Rust Coding, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Learn Rust Coding zawiera 3 lekcji w sumie.

Dlaczego bazy danych w aplikacjach internetowych?

Usługi internetowe często muszą trwale przechowywać dane i je odczytywać. Pomyśl o profilach użytkowników, katalogach produktów lub wpisach na blogu — te dane muszą znajdować się gdzieś poza pamięcią programu.

Bazy danych zapewniają uporządkowany sposób zarządzania tymi danymi, gwarantując, że są bezpieczne, spójne i dostępne. Integracja usługi internetowej w Rust z bazą danych to podstawowe zadanie w większości rzeczywistych aplikacji.

SQLx: asynchroniczny przyjaciel baz danych

Rust oferuje doskonałe narzędzia do obsługi baz danych. Dwa popularne rozwiązania to SQLx i Diesel.

  • SQLx: Asynchroniczny crate SQL napisany w całości w Rust, z zapytaniami sprawdzanymi podczas kompilacji. Często wybiera się go do asynchronicznych usług internetowych tworzonych za pomocą frameworków takich jak Tokio.
  • Diesel: Potężny ORM (Object-Relational Mapper), który zapewnia bardziej abstrakcyjny sposób interakcji z bazą danych, mapując struktury Rust bezpośrednio na tabele bazy danych. Zwykle działa synchronicznie.

W tej lekcji skupimy się na SQLx ze względu na jego dobre wsparcie dla programowania asynchronicznego, które dobrze pasuje do nowoczesnego tworzenia usług internetowych w Rust.

Konfiguracja SQLx: zależności

Przed napisaniem kodu należy dodać sqlx i tokio do pliku Cargo.toml projektu. tokio zapewnia środowisko uruchomieniowe potrzebne do asynchronicznego działania sqlx.

Na przykład, aby używać SQLite (prostej bazie danych opartej na pliku, przydatnej podczas lokalnego programowania) z SQLx, plik Cargo.toml może wyglądać tak:

[dependencies] sqlx = { version = "0.7", features = ["runtime-tokio-rustls", "sqlite"] } tokio = { version = "1", features = ["full"] }

Zwykle używa się również zmiennej środowiskowej DATABASE_URL do skonfigurowania parametrów połączenia z bazą danych.

Połącz się z pierwszą bazą danych

Nawiążmy połączenie z bazą danych SQLite przechowywaną w pamięci. SQLx używa pul połączeń, które efektywnie zarządzają wieloma połączeniami z bazą danych, aby obsługiwać współbieżne żądania w usłudze internetowej.

Uruchom ten przykład:

use sqlx::SqlitePool;
use tokio;

#[tokio::main]
async fn main() -> Result<(), sqlx::Error> {
    // Use an in-memory SQLite database for simplicity
    let database_url = "sqlite::memory:"; 
    let pool = SqlitePool::connect(&database_url).await?;
    println!("Successfully connected to the database!");

    // In a real web app, 'pool' would be passed around or stored in app state.

    Ok(())
}

Strukturyzowanie danych za pomocą tabel

Zanim będziemy mogli przechowywać dane, musimy zdefiniować schemat bazy danych za pomocą DDL (Data Definition Language). Utwórzmy prostą tabelę tasks.

Makro sqlx::query! pozwala osadzać kod SQL bezpośrednio w kodzie Rust. Wykonuje ono nawet kontrole SQL podczas kompilacji!

use sqlx::{SqlitePool, query};
use tokio;

#[tokio::main]
async fn main() -> Result<(), sqlx::Error> {
    let database_url = "sqlite::memory:";
    let pool = SqlitePool::connect(&database_url).await?;

    // Create a 'tasks' table if it doesn't exist
    query!(
        "CREATE TABLE IF NOT EXISTS tasks (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            description TEXT NOT NULL,
            completed BOOLEAN NOT NULL DEFAULT FALSE
        )"
    ).execute(&pool).await?;

    println!("Table 'tasks' created successfully!");
    Ok(())
}

Dodawanie nowych rekordów

Skoro mamy już tabelę, dodajmy dane! Użyjemy instrukcji INSERT z wiązaniem parametrów. Chroni to przed wstrzyknięciem SQL i zwiększa bezpieczeństwo zapytań.

Zwróć uwagę, że symbole zastępcze ? są używane dla parametrów, a wartości przekazuje się do .bind().

use sqlx::{SqlitePool, query};
use tokio;

#[tokio::main]
async fn main() -> Result<(), sqlx::Error> {
    let database_url = "sqlite::memory:";
    let pool = SqlitePool::connect(&database_url).await?;

    query!(
        "CREATE TABLE IF NOT EXISTS tasks (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            description TEXT NOT NULL,
            completed BOOLEAN NOT NULL DEFAULT FALSE
        )"
    ).execute(&pool).await?;

    // Insert a new task
    let description = "Learn SQLx";
    let completed = false;
    query!(
        "INSERT INTO tasks (description, completed) VALUES (?, ?)",
        description,
        completed
    ).execute(&pool).await?;

    println!("Task '{}' inserted successfully!", description);
    Ok(())
}

Pobieranie danych za pomocą SELECT

Aby pobrać dane z tabeli tasks, używamy instrukcji SELECT. SQLx udostępnia metody takie jak .fetch_all() i .fetch_one() do pobierania wyników.

Możesz iterować po zwróconych wierszach i uzyskiwać dostęp do kolumn według nazwy lub indeksu.

use sqlx::{SqlitePool, query};
use tokio;

#[tokio::main]
async fn main() -> Result<(), sqlx::Error> {
    let database_url = "sqlite::memory:";
    let pool = SqlitePool::connect(&database_url).await?;

    query!(
        "CREATE TABLE IF NOT EXISTS tasks (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            description TEXT NOT NULL,
            completed BOOLEAN NOT NULL DEFAULT FALSE
        )"
    ).execute(&pool).await?;

    query!(
        "INSERT INTO tasks (description, completed) VALUES (?, ?)",
        "Learn SQLx", false
    ).execute(&pool).await?;
    query!(
        "INSERT INTO tasks (description, completed) VALUES (?, ?)",
        "Build a web app", false
    ).execute(&pool).await?;

    // Fetch and print all tasks
    println!("\n--- All Tasks ---");
    let rows = query!("SELECT id, description, completed FROM tasks")
        .fetch_all(&pool).await?;

    for row in rows {
        println!("ID: {}, Desc: {}, Done: {}", 
            row.id, row.description, row.completed);
    }
    Ok(())
}

Bezpieczne typowo dane za pomocą struktur

Ręczne pobieranie danych z wierszy może prowadzić do błędów. Makro query_as! SQLx w połączeniu z #[derive(FromRow)] pozwala mapować wyniki zapytań bezpośrednio na struktury Rust!

Zapewnia to silne bezpieczeństwo typów i sprawia, że kod jest znacznie czytelniejszy oraz łatwiejszy w obsłudze.

use sqlx::{FromRow, SqlitePool, query, query_as};
use tokio;

#[derive(Debug, FromRow)]
struct Task {
    id: i64,
    description: String,
    completed: bool,
}

#[tokio::main]
async fn main() -> Result<(), sqlx::Error> {
    let database_url = "sqlite::memory:";
    let pool = SqlitePool::connect(&database_url).await?;

    query!(
        "CREATE TABLE IF NOT EXISTS tasks (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            description TEXT NOT NULL,
            completed BOOLEAN NOT NULL DEFAULT FALSE
        )"
    ).execute(&pool).await?;

    query!(
        "INSERT INTO tasks (description, completed) VALUES (?, ?)",
        "Learn SQLx", false
    ).execute(&pool).await?;

    // Fetch tasks directly into our Task struct
    println!("\n--- Tasks as Structs ---");
    let tasks = query_as::<_, Task>("SELECT id, description, completed FROM tasks")
        .fetch_all(&pool).await?;

    for task in tasks {
        println!("{:?}", task);
    }
    Ok(())
}

Modyfikowanie i usuwanie rekordów

Aktualizowanie i usuwanie danych przebiega podobnie jak ich wstawianie. Używa się instrukcji SQL UPDATE i DELETE z wiązaniem parametrów.

  • UPDATE: Zmienia istniejące wiersze na podstawie klauzuli WHERE.
  • DELETE: Usuwa wiersze na podstawie klauzuli WHERE.

Zawsze zachowuj ostrożność podczas używania klauzul WHERE w instrukcjach UPDATE i DELETE, aby uniknąć przypadkowej utraty danych!

use sqlx::{SqlitePool, query};
use tokio;

#[tokio::main]
async fn main() -> Result<(), sqlx::Error> {
    let database_url = "sqlite::memory:";
    let pool = SqlitePool::connect(&database_url).await?;

    query!(
        "CREATE TABLE IF NOT EXISTS tasks (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            description TEXT NOT NULL,
            completed BOOLEAN NOT NULL DEFAULT FALSE
        )"
    ).execute(&pool).await?;

    query!(
        "INSERT INTO tasks (description, completed) VALUES (?, ?)",
        "Finish lesson", false
    ).execute(&pool).await?;
    let task_id_to_update = 1;

    // Update a task
    query!(
        "UPDATE tasks SET completed = ? WHERE id = ?",
        true,
        task_id_to_update
    ).execute(&pool).await?;
    println!("Task {} updated.", task_id_to_update);

    // Delete a task (uncomment to run, careful with IDs after update)
    // let task_id_to_delete = 1;
    // query!(
    //     "DELETE FROM tasks WHERE id = ?",
    //     task_id_to_delete
    // ).execute(&pool).await?;
    // println!("Task {} deleted.", task_id_to_delete);

    Ok(())
}

Sprawdź swoją wiedzę o bazach danych

Które z poniższych stwierdzeń dotyczących SQLx w usługach internetowych w Rust są PRAWDZIWE?

Integracja z bazą danych: najważniejsze informacje

Wykonałeś ważny krok w tworzeniu niezawodnych usług internetowych w Rust, ucząc się integracji z bazą danych!

  • Trwałość: Bazy danych są niezbędne do przechowywania danych aplikacji.
  • SQLx: Asynchroniczny crate SQL ze sprawdzaniem zapytań podczas kompilacji, świetnie nadający się do usług internetowych.
  • Pule połączeń: Niezbędne do wydajnego i współbieżnego dostępu do bazy danych.
  • CRUD: Omówiliśmy tworzenie (INSERT), pobieranie (SELECT), aktualizowanie (UPDATE) i usuwanie (DELETE) danych.
  • Bezpieczeństwo typów: query_as! i #[derive(FromRow)] umożliwiają bezpieczne i wygodne mapowanie danych.

W następnej części możesz poznać integrację tych operacji na bazie danych z rzeczywistymi trasami internetowymi!

Często zadawane pytania

Czy lekcja „Integracja z bazami danych (SQLx/Diesel)” jest bezpłatna?

Tak — pełny tekst „Integracja z bazami danych (SQLx/Diesel)” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Learn Rust Coding, przejdź na CoddyKit PRO. Kurs Learn Rust Coding zawiera 3 lekcji w sumie.

Co nauczysz się w „Integracja z bazami danych (SQLx/Diesel)”?

Zintegrują Państwo usługę webową w Rust z bazami danych za pomocą popularnych ORM-ów lub kreatorów zapytań, takich jak SQLx czy Diesel. Ćwiczysz Learn Rust Coding z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć Learn Rust Coding?

Nie wymagamy żadnego doświadczenia. Learn Rust Coding w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 2 z 3.

Ile czasu zajmuje lekcja „Integracja z bazami danych (SQLx/Diesel)”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji Learn Rust Coding?

Tak. Każda lekcja Learn Rust Coding zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. REST API z Actix-web/Rocket
  2. Integracja z bazami danych (SQLx/Diesel)
  3. Uwierzytelnianie i autoryzacja
← Powrót do Learn Rust Coding