在Rust语言中,通过sqlx访问MySQL数据库
1. Cargo.toml配置文件❗ ❗
[package]
name = "rust-sqlx"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
sqlx = { version = "0.7", features = [ "runtime-async-std", "tls-native-tls", "mysql", "macros", "chrono" ] }
async-std = {version = "1.12.0", features = ["attributes"]}
chrono = "0.4.38"
\quad\quad
cargo.toml
配置文件可参考crates.io进行配置,但有几点值得注意❗ ❗ ❗:
- 如果选择
runtime-async-std
异步运行时,则需要开启它的attributes
的features
。否则在源文件中,入口函数处的#[async_std::main]
会报错。 sqlx
的features
中需要添加mysql
。否则use sqlx::mysql::MySqlPoolOptions;
会报错。sqlx
的features
中需要添加chrono
。 否则无法完成数据库中datetime
类型到chrono::NaiveDateTime
类型的转换。sqlx
的features
中需要添加macros
。否则query!()
以及query_as!()
等宏会报错。- 由于是简单的入门程序,
dotenvy
以及序列化等crates
暂时未引入。
2. 数据库中表结构
\quad\quad 在这里我的表结构如上所示。这个比较自由,根据自身实际情况选择即可。
3. 简单测试
\quad\quad 源文件主要修改自crates.io-sqlx中的示例程序。
❗❗❗ 注意,由于每个人的数据库密码,数据库名称,数据表的内容不尽相同,下面代码只具有参考意义,具体部分需要修改。
// use sqlx::postgres::PgPoolOptions;
use sqlx::mysql::MySqlPoolOptions;
use sqlx::Row;
use chrono::NaiveDateTime;
// etc.
/**
* 根据注释信息,我们提前在toml文件中设置以下内容,开启对应的feature
* async-std = {version = "1.12.0", features = ["attributes"]}
*/
#[async_std::main] // Requires the `attributes` feature of `async-std`
// or #[tokio::main]
// or #[actix_web::main]
async fn main() -> Result<(), sqlx::Error> {
let pool = MySqlPoolOptions::new()
.max_connections(5)
.connect("mysql://username:password@localhost/data_base_name").await?;
// `table_name`为你自己的表名称
let rows = sqlx::query("select * from table_name").fetch_all(&pool).await?;
// 如果想要使用`get`函数通过索引列名访问数据,需要提前引入`sqlx::Row`
/**
* get::<T, U>("column_name")
* 其中`T`对应于`rust`程序中的类型
* 其中`U`对应于查询类型,这里我们采用的是列名而不是索引,因此是`&str`
*/
for row in rows.iter() {
println!("id {}, name {}, create_time {}",
row.get::<u32, &str>("id"),
row.get::<String, &str>("name"),
row.get::<NaiveDateTime, &str>("create_time")
);
}
Ok(())
}
\quad\quad
执行cargo run --release
之后,在控制台便会输出
Finished release [optimized] target(s) in 0.19s
Running `target\release\rust-sqlx.exe`
id 1, name 学工部, create_time 2024-03-26 21:53:41
id 2, name 教研部, create_time 2024-03-26 21:53:41
id 3, name 咨询部, create_time 2024-03-26 21:53:41
id 4, name 就业部, create_time 2024-03-26 21:53:41
id 5, name 人事部, create_time 2024-03-26 21:53:41
4. FromRow
完成自动映射
\quad\quad
上述代码需要手动的将数据库查询结果取出,并转换为对应的rust
语言中的程序类型。显然是不符合实际情况的,需要想办法解决。
4.1 自定义结构体
\quad\quad 我们可以自定义一个结构体,让它代表数据表中记录数据的类型。
use chrono::NaiveDateTime;
use sqlx::FromRow;
#[derive(Debug, FromRow)]
pub struct Dept {
id: u32,
name: String,
create_time: NaiveDateTime,
update_time: NaiveDateTime,
}
\quad\quad
其中 FromRow
这个trait
完成了从表中的一条记录到程序中一个对象实例的转变。
4.2 代码分层
src
├─ dataobj
│ ├─ dept.rs
│ └─ mod.rs
└─ main.rs
\quad\quad 将代码划分成如上的属性结构。下面给出各部分的代码:
dataobj/dept.rs
部分
use chrono::NaiveDateTime;
use sqlx::FromRow;
#[derive(Debug, FromRow)]
pub struct Dept {
id: u32,
name: String,
create_time: NaiveDateTime,
update_time: NaiveDateTime,
}
dataobj/mod.rs
部分
pub mod dept;
main.rs
部分
use sqlx::mysql::MySqlPoolOptions;
use sqlx::Row;
use chrono::NaiveDateTime;
mod dataobj;
use dataobj::dept::Dept;
#[async_std::main] // Requires the `attributes` feature of `async-std`
async fn main() -> Result<(), sqlx::Error> {
let pool = MySqlPoolOptions::new()
.max_connections(5)
.connect("mysql://username:password@host/database_name").await?;
// `table_name`为你自己的表名称
let rows = sqlx::query("select * from table_name").fetch_all(&pool).await?;
println!("使用`query()`, 需要手动转换结果");
// 如果想要使用`get`函数通过索引列名访问数据,需要提前引入`sqlx::Row`
for row in rows.iter() {
println!("id {}, name {}, create_time {}",
row.get::<u32, &str>("id"),
row.get::<String, &str>("name"),
row.get::<NaiveDateTime, &str>("create_time")
);
}
println!();
let depts: Vec<Dept> = sqlx::query_as("select * from table_name").fetch_all(&pool).await?;
println!("使用`query_as()`, 将查询结果转为自定义结构体");
for dept in depts.iter() {
println!("{:#?}", dept);
}
println!();
let single_dept: Dept = sqlx::query_as("select * from table_name where id = ?")
.bind(1)
.fetch_one(&pool)
.await?;
println!("表中id为1的元素是: \n{:#?}", single_dept);
Ok(())
}
\quad\quad 输出结果如下
使用`query()`, 需要手动转换结果
id 1, name 学工部, create_time 2024-03-26 21:53:41
id 2, name 教研部, create_time 2024-03-26 21:53:41
id 3, name 咨询部, create_time 2024-03-26 21:53:41
id 4, name 就业部, create_time 2024-03-26 21:53:41
id 5, name 人事部, create_time 2024-03-26 21:53:41
使用`query_as()`, 将查询结果转为自定义结构体
Dept {
id: 1,
name: "学工部",
create_time: 2024-03-26T21:53:41,
update_time: 2024-03-26T21:53:41,
}
Dept {
id: 2,
name: "教研部",
create_time: 2024-03-26T21:53:41,
update_time: 2024-03-26T21:53:41,
}
Dept {
id: 3,
name: "咨询部",
create_time: 2024-03-26T21:53:41,
update_time: 2024-03-26T21:53:41,
}
Dept {
id: 4,
name: "就业部",
create_time: 2024-03-26T21:53:41,
update_time: 2024-03-26T21:53:41,
}
Dept {
id: 5,
name: "人事部",
create_time: 2024-03-26T21:53:41,
update_time: 2024-03-26T21:53:41,
}
表中id为1的元素是:
Dept {
id: 1,
name: "学工部",
create_time: 2024-03-26T21:53:41,
update_time: 2024-03-26T21:53:41,
}