今天,我們來學習 Rust 如何操作資料庫和如何使用 Rust 與不同的資料庫系統進行互動,實現高效的資料存取與查詢操作。Rust 以其安全性和高效能著稱,這些特性使其在資料庫程式設計領域表現出色,昨天有提到之前有面試一家使用Rust打造交易系統的公司,他們使用Rust的高效打造一年10TB的區塊鏈交易紀錄只需要幾秒就完成讀取和進行分析取得決策,可以從中看到Rust的未來潛力。
SQLx 是一個非同步的、純 Rust 實現的資料庫驅動程式,支援 MySQL、PostgreSQL、SQLite 等多種資料庫。
use sqlx::postgres::PgPoolOptions;
#[tokio::main]
async fn main() -> Result<(), sqlx::Error> {
let pool = PgPoolOptions::new()
.max_connections(5)
.connect("postgres://username:password@localhost/database_name").await?;
let row: (i64,) = sqlx::query_as("SELECT $1")
.bind(150_i64)
.fetch_one(&pool).await?;
assert_eq!(row.0, 150);
Ok(())
}
Diesel 是 Rust 最流行的 ORM(物件關聯對應)之一,提供了強大的查詢建構功能。
#[macro_use] extern crate diesel;
use diesel::prelude::*;
use diesel::pg::PgConnection;
use dotenv::dotenv;
use std::env;
table! {
users (id) {
id -> Int4,
name -> Varchar,
email -> Varchar,
}
}
#[derive(Queryable)]
struct User {
id: i32,
name: String,
email: String,
}
fn main() {
dotenv().ok();
let database_url = env::var("DATABASE_URL")
.expect("DATABASE_URL must be set");
let connection = PgConnection::establish(&database_url)
.expect(&format!("Error connecting to {}", database_url));
let results = users::table
.filter(users::name.eq("小明"))
.limit(5)
.load::<User>(&connection)
.expect("Error loading users");
println!("Displaying {} users", results.len());
for user in results {
println!("{} - {}", user.name, user.email);
}
}
MongoDB 是流行的 NoSQL 資料庫,Rust 提供了優秀的 MongoDB 驅動程式,我在車業新創和現在工作的AI新創公司都是使用MongoDB,我自己在接案時也滿常使用MongoDB,主要是彈性的SCHEMA。
use mongodb::{Client, options::ClientOptions};
use bson::doc;
#[tokio::main]
async fn main() -> mongodb::error::Result<()> {
let mut client_options = ClientOptions::parse("mongodb://localhost:27017").await?;
client_options.app_name = Some("MyApp".to_string());
let client = Client::with_options(client_options)?;
let db = client.database("mydb");
let collection = db.collection("books");
let doc = doc! {
"title": "The Rust Programming Language",
"author": "Steve Klabnik and Carol Nichols"
};
collection.insert_one(doc, None).await?;
Ok(())
}
Redis 是一個高效能的Key-value儲存系統,常用於快取和訊息佇列,我工作過的公司都有使用Redis來加速API的回應時間,也可以拿來當Queue。
use redis::Commands;
fn main() -> redis::RedisResult<()> {
let client = redis::Client::open("redis://127.0.0.1/")?;
let mut con = client.get_connection()?;
let _: () = con.set("my_key", "value")?;
let value: String = con.get("my_key")?;
println!("從 Redis 獲取的值: {}", value);
Ok(())
}
在處理高並發資料庫操作時,連線池和交易管理是提高效能與可靠性的關鍵。我們可以利用 Rust 的非同步特性實現高效的連線池和事務操作。
use sqlx::postgres::{PgPoolOptions, PgPool};
async fn create_pool() -> Result<PgPool, sqlx::Error> {
PgPoolOptions::new()
.max_connections(5)
.connect("postgres://username:password@localhost/database_name")
.await
}
async fn perform_transaction(pool: &PgPool) -> Result<(), sqlx::Error> {
let mut tx = pool.begin().await?;
sqlx::query("INSERT INTO users (name) VALUES ($1)")
.bind("小明")
.execute(&mut tx)
.await?;
sqlx::query("UPDATE accounts SET balance = balance - $1 WHERE user_id = $2")
.bind(100.0)
.bind(1)
.execute(&mut tx)
.await?;
tx.commit().await?;
Ok(())
}
#[tokio::main]
async fn main() -> Result<(), sqlx::Error> {
let pool = create_pool().await?;
perform_transaction(&pool).await?;
Ok(())
}
Rust 高效能的特性使其非常適合進行資料庫查詢效能優化。在處理大量資料時,我們可以通過有效的查詢策略來提升資料存取速度。
use sqlx::postgres::PgPool;
async fn optimized_query(pool: &PgPool) -> Result<Vec<(i32, String)>, sqlx::Error> {
sqlx::query_as("
SELECT id, name
FROM users
WHERE active = true
ORDER BY last_login DESC
LIMIT 10
")
.fetch_all(pool)
.await
}
#[tokio::main]
async fn main() -> Result<(), sqlx::Error> {
let pool = PgPoolOptions::new()
.max_connections(5)
.connect("postgres://username:password@localhost/database_name")
.await?;
let results = optimized_query(&pool).await?;
for (id, name) in results {
println!("使用者 ID: {}, 名稱: {}", id, name);
}
Ok(())
}
Rust 以其強大的性能和安全性,可以讓操作資料庫的速度和安全性大幅提升。其豐富的生態系統,包括 SQLx、Diesel 等工具,讓開發者能夠高效、安全地處理關聯式和非關聯式資料庫操作。同時,Rust 的型別系統也能幫助防止常見的資料庫錯誤,如 SQL 注入,確保程式碼的安全性和穩定性。