介绍:为什么Rust和数据库是完美组合
Rust是一种现代系统编程语言,它将C/C++的性能与编译器保证的内存安全性结合在一起。在开发后端服务、Web应用程序和微服务时,几乎总是需要与数据库进行交互。在本文中,我们将详细讨论如何与两种最流行的数据库类型一起工作:关系型PostgreSQL和文档型MongoDB。
我们将通过实际示例介绍连接、执行CRUD操作、事务和聚合。所有代码示例都使用Rust编写,并采用异步运行时tokio,以实现最大性能。
1. 项目设置和依赖安装
首先,创建一个新项目并添加必要的crate。打开终端并执行:
cargo new rust_db_example
cd rust_db_example
在Cargo.toml文件中添加依赖:
[dependencies]
tokio = { version = "1", features = ["full"] }
sqlx = { version = "0.7", features = ["runtime-tokio-rustls", "postgres"] }
mongodb = "2.8"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
chrono = { version = "0.4", features = ["serde"] }
现在项目结构已准备就绪。我们将使用sqlx连接PostgreSQL——这是一个支持编译时查询检查的异步驱动程序,以及官方mongodb驱动程序来操作MongoDB。
1.1. 通过sqlx连接PostgreSQL
编写一个用于操作PostgreSQL的模块。创建文件src/postgres.rs:
use sqlx::postgres::PgPoolOptions;
use sqlx::PgPool;
use anyhow::Result;
pub async fn connect_to_postgres() -> Result<PgPool> {
let database_url = "postgres://user:password@localhost:5432/mydb";
let pool = PgPoolOptions::new()
.max_connections(5)
.connect(database_url)
.await?;
println!("✅ 已连接到PostgreSQL");
Ok(pool)
}
// 定义用户模型
#[derive(Debug, sqlx::FromRow)]
pub struct User {
pub id: i32,
pub name: String,
pub email: String,
pub created_at: chrono::NaiveDateTime,
}
1.2. 连接MongoDB
创建文件src/mongodb.rs:
use mongodb::{Client, Collection, Database};
use mongodb::bson::{doc, Document};
use anyhow::Result;
pub async fn connect_to_mongodb() -> Result<(Database, Collection<Document>)> {
let client = Client::with_uri_str("mongodb://localhost:27017")?;
let database = client.database("mydb");
let collection = database.collection::<Document>("users");
println!("✅ 已连接到MongoDB");
Ok((database, collection))
}
2. PostgreSQL中的CRUD操作
现在实现基本操作:创建、读取、更新和删除记录。
2.1. 插入数据 (CREATE)
pub async fn create_user(pool: &PgPool, name: &str, email: &str) -> Result<User> {
let user = sqlx::query_as::<_, User>(
"INSERT INTO users (name, email) VALUES ($1, $2) RETURNING id, name, email, created_at"
)
.bind(name)
.bind(email)
.fetch_one(pool)
.await?;
println!("已创建用户: {:?}", user);
Ok(user)
}
2.2. 读取数据 (READ)
pub async fn get_user_by_id(pool: &PgPool, user_id: i32) -> Result<Option<User>> {
let user = sqlx::query_as::<_, User>(
"SELECT id, name, email, created_at FROM users WHERE id = $1"
)
.bind(user_id)
.fetch_optional(pool)
.await?;
match user {
Some(u) => println!("找到用户: {:?}", u),
None => println!("未找到id={}的用户"