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
- REST API z Actix-web/Rocket
- Integracja z bazami danych (SQLx/Diesel)
- Uwierzytelnianie i autoryzacja