rust使用sqlx示例

B站影视 欧美电影 2025-09-23 12:28 1

摘要:use std::env;use async_trait::async_trait;use sqlx::Error;use sqlx::mysql::MySqlPool;pub struct UserDo { pub id:u64, pub username:

use std::env;use async_trait::async_trait;use sqlx::Error;use sqlx::mysql::MySqlPool;pub struct UserDo { pub id:u64, pub username:String, pub email:String, pub password:String,} impl UserDo { pub fn new (username:String, email:String, password:String) -> Self { Self{ id:0, username, email, password } } } #[async_trait] pub trait UserRepo: Send + Sync { async fn add_user(&self, _: UserDo) ->Result; } pub struct UserPersistence { pub pool:MySqlPool, } impl UserPersistence { pub async fn new -> Result { let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set"); println!("DATABASE_URL: {}", &database_url); let pool = MySqlPool::connect(&database_url).await?; Ok(Self { pool }) } } #[async_trait] impl UserRepo for UserPersistence { async fn add_user(&self, user: UserDo) -> Result{ let result = sqlx::query!( "INSERT INTO users (username, email, password) VALUES (?, ?, ?)", user.username, user.email, user.password ) .execute(&self.pool) .await?;let user_id = result.6824179; #技术分享let inserted_user: UserDo = sqlx::query_as!( UserDo, "SELECT id, username, email, password FROM users WHERE id = ?", user_id ) .fetch_one(&self.pool) .await?;Ok(inserted_user) } } #[tokio::main] async fn main -> Result> { dotenv::dotenv.ok; let user_service = UserPersistence::new.await?;let user_do = UserDo::new("sssacsa".into, "889999@qq.com".into, "opass".into);match user_service.add_user(user_do).await { Ok(inserted_user) => { println!("User added successfully: ID {}", inserted_user.id); Ok() } Err(e) => { eprintln!("Failed to add user: {}", e); Err(e.into) } } }

执行命令

该示例主要用到的包就配置文件如下

async-trait:提供异步支持dotenv:提供配置文件读取支持sqlx :提供数据库交互支持tokio:Rust 编程语言的异步运行时[dependencies]async-trait = "0.1.89"dotenv = "0.15.0"sqlx = { version = "0.8.6",features = ["mysql","runtime-async-std-native-tls"] }tokio = { version = "1.47.1", features = ["rt", "rt-multi-thread", "macros"] }

项目中引入这些包,

use std::env;use async_trait::async_trait;use sqlx::Error;use sqlx::mysql::MySqlPool;

以下 do 实体是用于与数据库交互的实体,需要注意的是在实际企业级应用开发中实体肯定不会这么简单,这里只是为了给初学者示例,方便大家理解所以字段相对较少。

pub struct UserDo { pub id:u64, pub username:String, pub email:String, pub password:String,} impl UserDo { pub fn new (username:String, email:String, password:String) -> Self { Self{ id:0, username, email, password } } }

上面的代码 impl UserDo 中 new 函数是结构体(UserDo)的 有参构造 方便后面给结构体赋值。

定义仓储接口

该接口主要实现对用户这个模块的新增功能

#[async_trait] pub trait UserRepo: Send + Sync { async fn add_user(&self, _: UserDo) ->Result; }

持久化层主要是负责对仓储接口的实现

pub struct UserPersistence { pub pool:MySqlPool,}impl UserPersistence { pub async fn new -> Result { let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set"); println!("DATABASE_URL: {}", &database_url); let pool = MySqlPool::connect(&database_url).await?; Ok(Self { pool }) }}#[async_trait] impl UserRepo for UserPersistence { async fn add_user(&self, user: UserDo) -> Result{ let result = sqlx::query!( "INSERT INTO users (username, email, password) VALUES (?, ?, ?)", user.username, user.email, user.password ) .execute(&self.pool) .await?;let user_id = result.6824179;let inserted_user: UserDo = sqlx::query_as!( UserDo, "SELECT id, username, email, password FROM users WHERE id = ?", user_id ) .fetch_one(&self.pool) .await?;Ok(inserted_user) } }

上面这段代码有点多,不用急咱们分段来解释 首先这段代码,这里可以看到我们也是定义了一个结构体实现了它的 构造方法 ,但是与上面不同的是我们的构造方法并没有传入参数,这里其实我们读取的是环境变量,.env 文件。这里使用到的是 rust 的一个插件,dotenv;你可以把这里理解为像 C#读取 appsetting.json 文件一样。MySqlPool 是一个 sqlx 提供的 mysql 连接池类型,

它的作用就是读取到配置文件中的数据库连接字符串。创建连接池

pub struct UserPersistence { pub pool:MySqlPool,}impl UserPersistence { pub async fn new -> Result { let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set"); println!("DATABASE_URL: {}", &database_url); let pool = MySqlPool::connect(&database_url).await?; Ok(Self { pool }) }}

注意:.env 文件文件是自己创建的文件,与 Cargo.toml 同级

DATABASE_URL=mysql://用户名:密码@localhost/库名

下面这段代码是实现上面定义的用户仓储实现持久化到数据库中,传入的是一个 UserDo 实体,返回值是新插入的这个 UserDo,如果报错的话会返回 Error 信息

#[async_trait] impl UserRepo for UserPersistence { async fn add_user(&self, user: UserDo) -> Result{ let result = sqlx::query!( "INSERT INTO users (username, email, password) VALUES (?, ?, ?)", user.username, user.email, user.password ) .execute(&self.pool) .await?;let user_id = result.6824179;let inserted_user: UserDo = sqlx::query_as!( UserDo, "SELECT id, username, email, password FROM users WHERE id = ?", user_id ) .fetch_one(&self.pool) .await?;Ok(inserted_user) } }

在 main 函数中我进行方法调用

#[tokio::main]async fn main -> Result> { dotenv::dotenv.ok; let user_service = UserPersistence::new.await?;let user_do = UserDo::new("sssacsa".into, "889999@qq.com".into, "opass".into);match user_service.add_user(user_do).await { Ok(inserted_user) => { println!("User added successfully: ID {}", inserted_user.id); Ok() } Err(e) => { eprintln!("Failed to add user: {}", e); Err(e.into) } } }

接下来咱们来解释一下上面这段代码:

这句代码看起来很突兀对吧,但是它是不能缺少的,它的作用是把 .env 文件里的 KEY=value 逐行读出来,塞进当前进程的「环境变量表」里,之后 std::env::var("KEY") 就能拿到值。如果这段代码没有我们上面读取数据库连接字符串哪里就会报错。

match user_service.add_user(user_do).await...

这段代码的作用是接受方法返回值,还记得我们 add_user 函数中使用的返回类型是什么吗?是 Result;Result 有两个变体,一个是用户实体,一个是错误实体。我们使用 match 表达式就相当于 c# 中的 if 判断,

如果方法执行成功了咱们再 Ok 里就接收它的返回值,然后打印,如果失败了就程序 panic 直接恐慌,程序直接死给你看然后把错误信息给提示出来。

首先执行进行安装;注意:这里我使用的是 mysql 所以代码最后填写的是 mysql,如果你使用的是 pgsql,这里需要修改

cargo install sqlx-cli --no-default-features --features native-tls,mysql

当安装完成后我们可以在项目控制台执行迁移命令;当执行完成之后会在项目中生成一个 migrations 文件夹,里面有我们创建的迁移脚本 create_users_table ;注意:create_users_table 这个是 可以自定义 的迁移脚本文件名。

sqlx migrate add create_users_table

这里生成的迁移脚本是空的,需要自己手动写 当迁移脚本添加好了之后 执行以下命令运行迁移脚本

sqlx migrate run

执行结束后我们可以在库里看到有一点变化,sqlx 会创建一个迁移记录表

来源:墨码行者

相关推荐