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
的版本兼容性);