Integrasi Database
Menyimpan data secara persisten
Integrasi Database adalah pelajaran Learn Rust Coding gratis di CoddyKit. Ini adalah pelajaran 3 dari 4. Kamu bisa membaca pelajaran lengkapnya di bawah secara gratis — lalu praktikkan langsung di browser dengan editor kode bawaan dan tutor AI 24/7. Ini adalah bagian dari jalur belajar Learn Rust Coding, dan progresmu tersinkronisasi di web dan aplikasi CoddyKit. Kursus Learn Rust Coding mencakup 4 pelajaran total.
Menyimpan Data secara Persisten
Sejauh ini, API kita menyimpan data di memori, sehingga data hilang saat dimulai ulang. Layanan nyata memerlukan basis data. Dalam pelajaran ini, kita menghubungkan API Axum ke PostgreSQL menggunakan sqlx, toolkit SQL asinkron untuk Rust yang diperiksa saat kompilasi.
Anda akan mempelajari pool koneksi, query, pemetaan baris ke struct, dan penggunaan pool sebagai state bersama.
Menambahkan sqlx
Tambahkan sqlx dengan fitur yang diperlukan: runtime, TLS, dan driver basis data. Berikut penyiapan Postgres menggunakan Tokio.
// Cargo.toml
// [dependencies]
// sqlx = { version = "0.7", features = [
// "runtime-tokio", "tls-rustls", "postgres", "macros"
// ] }Pool Koneksi
Membuka koneksi baru untuk setiap permintaan berjalan lambat. Pool koneksi menyimpan sekumpulan koneksi yang dapat digunakan kembali. PgPoolOptions membuatnya dari URL basis data. Pool ini murah untuk di-clone (secara internal menggunakan penghitungan referensi), sehingga ideal sebagai state bersama.
use sqlx::postgres::PgPoolOptions;
async fn make_pool(url: &str) -> sqlx::PgPool {
PgPoolOptions::new()
.max_connections(5)
.connect(url)
.await
.expect("failed to connect")
}Pool sebagai State Aplikasi
Teruskan pool ke Axum dengan .with_state(pool). Handler kemudian menerima State(pool): State<PgPool>. Karena pool murah untuk di-clone, setiap permintaan berbagi koneksi dasar yang sama.
use axum::{routing::get, Router};
use sqlx::PgPool;
fn build(pool: PgPool) -> Router {
Router::new()
.route("/todos", get(list_todos))
.with_state(pool)
}Menjalankan Query
Fungsi sqlx::query menjalankan SQL mentah. Ikat parameter dengan .bind(value) untuk mencegah injeksi SQL; Postgres menggunakan placeholder $1, $2. Gunakan .execute(&pool) untuk penulisan yang tidak mengembalikan baris.
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(())
}Memetakan Baris ke Struct
Turunkan sqlx::FromRow pada model Anda agar hasil query dapat langsung dipetakan ke dalamnya. Gunakan query_as::<_, Todo> dengan fetch_all untuk memperoleh Vec<Todo>, atau fetch_one untuk satu baris.
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)
}Handler yang Membaca Basis Data
Gabungkan semua bagian: handler mengambil pool dari state, menjalankan query, lalu mengembalikan JSON. Petakan error basis data ke status 500 agar klien menerima respons yang rapi, bukan 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),
}
}Mengembalikan Baris yang Disisipkan
Postgres dapat mengembalikan baris yang baru saja disisipkan dengan RETURNING. Gabungkan dengan query_as dan fetch_one untuk memperoleh record baru, termasuk id yang dibuat secara otomatis, dalam satu perjalanan pulang-pergi.
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)
}Migrasi
Skema harus tersedia sebelum query dijalankan. sqlx mendukung migrasi: file SQL dalam folder migrations/ yang diterapkan secara berurutan. Jalankan saat inisialisasi dengan sqlx::migrate!() agar basis data baru disiapkan secara otomatis.
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.Transaksi
Ketika beberapa operasi penulisan harus berhasil bersama-sama, bungkus operasi tersebut dalam transaksi. Mulai dengan pool.begin(), jalankan query pada handle transaksi, lalu lakukan commit. Jika transaksi dihapus tanpa di-commit, sqlx secara otomatis melakukan rollback sehingga data tetap konsisten.
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(())
}Konfigurasi dan Rahasia
Jangan pernah menulis kredensial basis data secara langsung dalam kode. Baca DATABASE_URL dari lingkungan, yang sering dimuat dari file .env dengan crate dotenvy selama pengembangan. Dalam produksi, platform menyediakannya sebagai variabel lingkungan.
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
}Pemeriksaan Singkat
Uji pemahaman Anda tentang integrasi basis data.
Ringkasan
Anda telah mengintegrasikan basis data:
- Gunakan kumpulan koneksi
PgPooldan bagikan melalui.with_state. query/executeuntuk penulisan;query_asdenganFromRowuntuk pembacaan bertipe.- Selalu ikat parameter untuk mencegah injeksi SQL.
RETURNINGmengambil baris yang disisipkan; transaksi mengelompokkan penulisan secara atomik.- Jalankan migrasi saat memulai dan baca
DATABASE_URLdari lingkungan.
Pertanyaan yang Sering Diajukan
Apakah pelajaran “Integrasi Database” gratis?
Ya — teks lengkap “Integrasi Database” gratis dibaca di sini di web. Untuk praktiknya secara interaktif (editor kode bawaan dan tutor AI 24/7) dan buka sisa kursus Learn Rust Coding, upgrade ke CoddyKit PRO. Kursus Learn Rust Coding mencakup 4 pelajaran total.
Apa yang akan aku pelajari di “Integrasi Database”?
Menyimpan data secara persisten Kamu berlatih Learn Rust Coding dengan kode praktik yang langsung kamu jalankan di browser, dan tutor AI 24/7 menjawab pertanyaanmu saat kamu mengerjakan pelajaran ini.
Apakah aku perlu pengalaman untuk memulai Learn Rust Coding?
Tidak diperlukan pengalaman sebelumnya. Learn Rust Coding di CoddyKit dirancang untuk pemula hingga pelajar tingkat lanjut, jadi kamu bisa memulai di sini atau dari awal dan belajar sesuai kecepatan kamu sendiri. Ini adalah pelajaran 3 dari 4.
Berapa lama pelajaran “Integrasi Database” memakan waktu?
Sebagian besar pelajaran CoddyKit memakan waktu sekitar 5–10 menit. Setiap pelajaran ringkas dan interaktif, jadi kamu membuat kemajuan stabil dan melanjutkan dari tempat kamu tinggalkan di web dan aplikasi.
Bisakah aku menulis dan menjalankan kode dalam pelajaran Learn Rust Coding ini?
Ya. Setiap pelajaran Learn Rust Coding menyertakan editor kode bawaan, jadi kamu menulis dan menjalankan kode nyata langsung di browser dan mendapatkan umpan balik AI instan — tidak diperlukan penyiapan lokal.
Semua pelajaran dalam kursus ini
- Penyiapan Proyek
- Endpoint dan Model
- Integrasi Database
- Menguji API