使用 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 查询逻辑)来组织代码,实现了用户管理系统的基本功能。

相关推荐
开心工作室_kaic2 小时前
springboot548二手物品交易boot代码(论文+源码)_kaic
前端·数据库·vue.js·后端·html5
Demons_kirit5 小时前
Spring Boot + Redis + Sa-Token
spring boot·redis·后端
milo.qu8 小时前
二、CSS基础
前端·javascript·css
小周同学:8 小时前
elementui table 表格 分页多选,保持选中状态
前端·vue.js·elementui
freejackman9 小时前
Redis快速入门
数据库·redis·缓存
小嘟嚷ovo10 小时前
vue中的h
前端·javascript·vue.js
snows_l10 小时前
vue3 拆信封动画
前端·gif
G佳伟10 小时前
vue字符串的数字比较大小有问题
android·前端·vue.js
ice___Cpu10 小时前
Redis - 7 ( 11000 字 Redis 入门级教程 )
数据库·redis·bootstrap
l1x1n010 小时前
【Hackthebox 中英 Write-Up】Web Request | 分析 HTTP 请求和响应
前端·网络协议·http