使用 Actix-Web、SQLx 和 Redis 构建高性能 Rust Web 服务:模块化结构

使用 Actix-Web、SQLx 和 Redis 构建高性能 Rust Web 服务:模块化结构

在本教程中,我们将详细介绍如何在 Windows 系统上使用 Actix-Web 框架、SQLx 数据库工具和 Redis 缓存来构建一个高性能的 Rust Web 服务。我们将创建一个用户管理系统,包括获取单个用户、创建用户和获取所有用户的功能,并通过模块化结构来组织代码,使其更加清晰和易于维护。

什么是 Actix-Web

Actix-Web 是一个用于构建 Web 应用程序的高性能、异步框架,基于 Rust 语言。它具有以下特点:

  • 异步 :使用 tokioasync-std 等异步运行时,提供高性能和高并发处理能力。
  • 中间件:支持中间件机制,可以方便地扩展功能。
  • 路由:灵活的路由机制,支持路径参数、查询参数等多种路由方式。
  • 类型安全:利用 Rust 的类型系统,确保代码的类型安全性和健壮性。
  • 社区支持:拥有活跃的开发者社区和丰富的文档资源。

准备工作

安装 Rust 和 Cargo

首先,确保你已经安装了 Rust 编程语言和 Cargo 包管理器。你可以在 Rust 官网 上找到适用于 Windows 的安装指南。按照提示运行 Rust 安装程序,并在安装过程中选择安装 Visual C++ 构建工具。

安装 MySQL

安装 MySQL 数据库,并设置好对应的环境变量。你可以从 MySQL 官网 下载适用于 Windows 的安装程序,并按照官方指南进行安装。

安装 Redis

安装 Redis,并设置好对应的环境变量。你可以从 Redis 官网 下载 Windows 版本的安装程序,并按照官方指南进行安装。

创建项目

首先,使用 Cargo 创建一个新的 Rust 项目:

sh 复制代码
cargo new my_actix_app
cd my_actix_app

添加依赖项

编辑 Cargo.toml 文件,添加所需的依赖项:

toml 复制代码
[package]
name = "my_actix_app"
version = "0.1.0"
edition = "2021"

[dependencies]
actix-web = "4.0"
sqlx = { version = "0.5", features = ["mysql", "runtime-tokio-native-tls"] }
redis = "0.26"
dotenv = "0.15"
serde = { version = "1.0", features = ["derive"] }
tokio = { version = "1", features = ["full"] }

创建目录结构

为了更好地组织代码,我们可以创建一个 models 目录来存放数据模型,以及一个 db 目录来存放 SQL 查询逻辑。创建以下目录结构:

复制代码
my_actix_app/
├── src/
│   ├── main.rs
│   ├── models/
│   │   └── user.rs
│   └── db/
│       └── user_queries.rs
├── .env
└── Cargo.toml

创建数据模型

src/models/user.rs 文件中创建用户数据模型:

rust 复制代码
use serde::{Deserialize, Serialize};

#[derive(Debug, Serialize, Deserialize)]
pub struct User {
    pub id: i32,
    pub name: String,
    pub email: String,
}

创建 SQL 查询逻辑

src/db/user_queries.rs 文件中创建用户相关的 SQL 查询逻辑:

rust 复制代码
use sqlx::mysql::MySqlPool;
use crate::models::User;
use sqlx::Error;

// 获取单个用户
pub async fn get_user_by_id(pool: &MySqlPool, user_id: i32) -> Result<Option<User>, Error> {
    sqlx::query_as!(
        User,
        r#"
        SELECT id, name, email FROM users WHERE id = ?
        "#,
        user_id
    )
    .fetch_optional(pool)
    .await
}

// 创建新用户
pub async fn create_user(pool: &MySqlPool, name: String, email: String) -> Result<User, Error> {
    let result = sqlx::query!(
        r#"
        INSERT INTO users (name, email) VALUES (?, ?)
        "#,
        name,
        email
    )
    .execute(pool)
    .await?;

    Ok(User {
        id: result.last_insert_id() as i32,
        name,
        email,
    })
}

// 获取所有用户
pub async fn get_all_users(pool: &MySqlPool) -> Result<Vec<User>, Error> {
    sqlx::query_as!(
        User,
        r#"
        SELECT id, name, email FROM users
        "#
    )
    .fetch_all(pool)
    .await
}

编写代码

src/main.rs 文件中编写代码。以下是完整的代码示例,并在关键部分添加了注解:

rust 复制代码
use actix_web::{get, post, web, App, HttpResponse, HttpServer, Responder};
use serde::{Deserialize, Serialize};
use sqlx::mysql::MySqlPool;
use redis::Client as RedisClient;
use std::sync::Arc;
use dotenv::dotenv;
use serde_json::json;
use std::env;

// 引入 models 目录中的 User 结构体
mod models;
use models::User;

// 引入 db 目录中的用户查询逻辑
mod db;
use db::user_queries::{get_user_by_id, create_user, get_all_users};

// 定义 AppState 结构体,用于存储数据库连接和 Redis 客户端
struct AppState {
    db: MySqlPool,
    redis: RedisClient,
}

// 获取单个用户
#[get("/users/{id}")]
async fn get_user(path: web::Path<i32>, data: web::Data<AppState>) -> impl Responder {
    let user_id = path.into_inner();
    let pool = &data.db;

    // 查询用户
    let query_result = get_user_by_id(pool, user_id).await;

    match query_result {
        Ok(Some(user)) => HttpResponse::Ok().json(user),
        Ok(None) => HttpResponse::NotFound().body("用户未找到"),
        Err(_) => HttpResponse::InternalServerError().body("获取用户时出错"),
    }
}

// 创建新用户
#[post("/users")]
async fn create_user_handler(user: web::Json<User>, data: web::Data<AppState>) -> impl Responder {
    let pool = &data.db;

    // 插入用户
    let insert_result = create_user(pool, user.name.clone(), user.email.clone()).await;

    match insert_result {
        Ok(user) => HttpResponse::Created().json(user),
        Err(_) => HttpResponse::InternalServerError().body("创建用户时出错"),
    }
}

// 获取所有用户
#[get("/users")]
async fn get_all_users_handler(data: web::Data<AppState>) -> impl Responder {
    let pool = &data.db;

    // 查询所有用户
    let query_result = get_all_users(pool).await;

    match query_result {
        Ok(users) => HttpResponse::Ok().json(users),
        Err(_) => HttpResponse::InternalServerError().body("获取用户时出错"),
    }
}

// 主函数,设置数据库连接和 Redis 客户端,并启动 HTTP 服务器
#[actix_web::main]
async fn main() -> std::io::Result<()> {
    dotenv().ok();

    // 从环境变量中读取数据库 URL
    let database_url = env::var("DATABASE_URL").expect("DATABASE_URL 必须设置");
    // 创建数据库连接池
    let pool = MySqlPool::connect(&database_url).await.expect("创建连接池失败");

    // 从环境变量中读取 Redis URL
    let redis_url = env::var("REDIS_URL").expect("REDIS_URL 必须设置");
    // 创建 Redis 客户端
    let redis_client = RedisClient::open(redis_url).expect("创建 Redis 客户端失败");

    println!("服务器运行在 http://127.0.0.1:8880");

    // 启动 HTTP 服务器
    HttpServer::new(move || {
        App::new()
            .app_data(web::Data::new(AppState {
                db: pool.clone(),
                redis: redis_client.clone(),
            }))
            .service(get_user)
            .service(create_user_handler)
            .service(get_all_users_handler)
    })
    .bind(("127.0.0.1", 8880))?
    .run()
    .await
}

创建数据库表

在 MySQL 数据库中创建一个名为 users 的表,包括 idnameemail 字段。你可以使用以下 SQL 语句来创建表:

sql 复制代码
CREATE TABLE users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(255) NOT NULL,
    email VARCHAR(255) NOT NULL
);

设置环境变量

在项目的根目录下创建一个 .env 文件,并添加以下内容:

复制代码
DATABASE_URL=mysql://username:password@localhost/database_name
REDIS_URL=redis://127.0.0.1/

请将 usernamepassworddatabase_name 替换为你的 MySQL 数据库的实际值。

运行项目

最后,使用 Cargo 运行项目,并访问 http://127.0.0.1:8880 来测试 API 接口的功能。

sh 复制代码
cargo run

通过本教程,你将学会如何在 Windows 系统上使用 Actix-Web、SQLx 和 Redis 构建一个高性能的 Rust Web 服务,并且通过合理的项目结构(如使用 models 目录存放数据模型,db 目录存放 SQL 查询逻辑)来组织代码,实现了用户管理系统的基本功能。

相关推荐
崔庆才丨静觅7 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
陌上丨7 小时前
Redis的Key和Value的设计原则有哪些?
数据库·redis·缓存
passerby60617 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了8 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅8 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅8 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅8 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment8 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅9 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊9 小时前
jwt介绍
前端