iT邦幫忙

2024 iThome 鐵人賽

DAY 19
0
Software Development

Rust 學得動嗎系列 第 19

[Day 19] Rust 如何操作資料庫

  • 分享至 

  • xImage
  •  

今天,我們來學習 Rust 如何操作資料庫和如何使用 Rust 與不同的資料庫系統進行互動,實現高效的資料存取與查詢操作。Rust 以其安全性和高效能著稱,這些特性使其在資料庫程式設計領域表現出色,昨天有提到之前有面試一家使用Rust打造交易系統的公司,他們使用Rust的高效打造一年10TB的區塊鏈交易紀錄只需要幾秒就完成讀取和進行分析取得決策,可以從中看到Rust的未來潛力。

1. 使用 SQLx 進行資料庫操作

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

2. 使用 Diesel 進行 ORM 操作

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

3. 使用 mongodb 操作 MongoDB

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

4. 使用 redis 操作 Redis

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

5. 實現連線池(Connection pool)與交易管理(Transaction manage)

在處理高並發資料庫操作時,連線池和交易管理是提高效能與可靠性的關鍵。我們可以利用 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(())
}

6. 實現查詢效能優化

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 注入,確保程式碼的安全性和穩定性。


上一篇
[Day 18] Rust 在網路程式設計中的應用
下一篇
[Day 20] Rust 在機器學習和資料科學中的應用
系列文
Rust 學得動嗎30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言