Rust語言在Linux下的數據庫操作指南
在Linux(如Ubuntu/Debian)上,通過以下命令安裝Rust工具鏈(rustc編譯器、cargo包管理器)及依賴:
sudo apt update && sudo apt install -y build-essential curl git
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source $HOME/.cargo/env
驗證安裝:
rustc --version # 查看Rust編譯器版本
cargo --version # 查看包管理器版本
sudo apt install -y postgresql postgresql-contrib # 安裝PostgreSQL及擴展
sudo -u postgres createuser --interactive # 創建數據庫用戶(交互式輸入用戶名/密碼)
sudo -u postgres createdb testdb # 為用戶創建數據庫
注意:若使用SQLite(嵌入式數據庫),無需額外安裝服務,直接通過Rust庫操作即可。
Rust生態中有多個成熟的數據庫庫,根據需求選擇:
rusqlite(SQLite)、diesel(PostgreSQL/MySQL/SQLite,支持查詢構建)、mysql(MySQL)。tokio-postgres(PostgreSQL,配合tokio運行時)、sqlx(PostgreSQL/MySQL/SQLite,異步+編譯時SQL檢查)、mongodb(NoSQL數據庫)。Diesel(類型安全查詢構建)、SQLx(異步ORM,支持編譯時SQL驗證)。在項目根目錄的Cargo.toml中添加rusqlite(支持SQLite)和serde(可選,用于數據序列化):
[dependencies]
rusqlite = { version = "0.26", features = ["bundled"] } # bundled包含SQLite源碼,無需系統安裝
serde = { version = "1.0", features = ["derive"] } # 可選,用于結構體序列化
use rusqlite::{params, Connection, Result};
use serde::{Serialize, Deserialize};
// 定義用戶結構體(可選,用于數據映射)
#[derive(Debug, Serialize, Deserialize)]
struct User {
id: i32,
name: String,
age: i32,
}
fn main() -> Result<()> {
// 1. 連接數據庫(若文件不存在則自動創建)
let conn = Connection::open("test.db")?;
// 2. 創建表(IF NOT EXISTS避免重復創建)
conn.execute(
"CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
age INTEGER
)",
[],
)?;
// 3. 插入數據(參數化查詢,防止SQL注入)
conn.execute(
"INSERT INTO users (name, age) VALUES (?1, ?2)",
params![ "Alice", 30 ],
)?;
// 4. 查詢數據(使用query_map映射到結構體)
let mut stmt = conn.prepare("SELECT id, name, age FROM users")?;
let user_iter = stmt.query_map([], |row| {
Ok(User {
id: row.get(0)?,
name: row.get(1)?,
age: row.get(2)?,
})
})?;
for user in user_iter {
println!("User: {:?}", user?); // 輸出:User { id: 1, name: "Alice", age: 30 }
}
Ok(())
}
關鍵點:
params![...])是防止SQL注入的核心手段;?操作符用于錯誤傳播,簡化錯誤處理;bundled特性避免依賴系統SQLite庫,提升可移植性。在Cargo.toml中添加tokio(異步運行時)和tokio-postgres(PostgreSQL客戶端):
[dependencies]
tokio = { version = "1.0", features = ["full"] } # 異步運行時
tokio-postgres = "0.7" # PostgreSQL異步客戶端
use tokio_postgres::{NoTls, Error};
#[tokio::main] // 標記異步主函數
async fn main() -> Result<(), Error> {
// 1. 連接數據庫(異步)
let (client, connection) = tokio_postgres::connect(
"host=localhost user=postgres dbname=testdb", // 連接字符串
NoTls, // 無TLS加密(生產環境建議啟用)
).await?;
// 2. 后臺運行連接任務(處理連接錯誤)
tokio::spawn(async move {
if let Err(e) = connection.await {
eprintln!("Connection error: {}", e);
}
});
// 3. 執行查詢(異步)
let rows = client.query("SELECT id, name, age FROM users", &[]).await?;
// 4. 處理結果
for row in rows {
let id: i32 = row.get(0);
let name: String = row.get(1);
let age: i32 = row.get(2);
println!("ID: {}, Name: {}, Age: {}", id, name, age);
}
Ok(())
}
關鍵點:
#[tokio::main]宏將主函數轉換為異步函數,需配合tokio運行時;.await關鍵字,避免阻塞線程;NoTls為native_tls或rustls)。在Cargo.toml中添加diesel(支持PostgreSQL/MySQL/SQLite)和dotenv(環境變量管理):
[dependencies]
diesel = { version = "1.4", features = ["postgres"] } # 替換為mysql或sqlite適配對應數據庫
dotenv = "0.15" # 管理環境變量
創建.env文件(項目根目錄):
DATABASE_URL=postgres://postgres:your_password@localhost/testdb
運行diesel setup初始化數據庫遷移目錄,然后創建遷移:
diesel migration generate create_users
編輯遷移文件(migrations/xxxx_create_users/up.sql):
CREATE TABLE users (
id SERIAL PRIMARY KEY,
name VARCHAR(255) NOT NULL,
age INTEGER
);
運行遷移:
diesel migration run
#[macro_use] extern crate diesel;
use diesel::prelude::*;
use dotenv::dotenv;
use std::env;
// 定義模型
#[derive(Queryable, Insertable)]
#[table_name = "users"]
struct User {
name: String,
age: i32,
}
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 new_user = User { name: "Bob".to_string(), age: 25 };
diesel::insert_into(users::table)
.values(&new_user)
.execute(&connection)
.expect("Error saving new user");
// 查詢數據
let results = users::table
.filter(users::name.like("%B%"))
.limit(5)
.load::<User>(&connection)
.expect("Error loading users");
println!("Found {} users", results.len());
for user in results {
println!("Name: {}, Age: {}", user.name, user.age);
}
}
關鍵點:
schema.rs自動生成表結構綁定,避免硬編碼SQL;filter、limit),編譯時檢查SQL合法性;params![...]或bind方法,避免SQL注入;Result類型和?操作符,或自定義錯誤類型(如thiserror庫)封裝數據庫錯誤。r2d2庫管理數據庫連接(如r2d2_sqlite、r2d2_postgres),避免頻繁創建/銷毀連接;transaction)批量插入/更新數據,減少數據庫往返次數;CREATE INDEX idx_name ON users(name)),提升查詢速度。sudo systemctl status postgresql)、連接字符串是否正確(主機、端口、用戶名、密碼、數據庫名);cargo tree查看依賴樹,解決版本沖突(如diesel與tokio的版本兼容性);