rust使用mysql_async库

未分类
4.7k 词

在rust中使用mysql可以使用mysql_async实现,mysql_async库是基于Tokio的异步MySql客户端库。

添加Tokio库

由于mysql_async是基于Tokio开发的,因此需要导入Tokio,同时也能更方便异步开发
Cargo.toml中的[dependencies]下加入

1
tokio = { version = "*", features = ["full"] }

添加mysql_async库

在当前目录执行

1
cargo add mysql_async

即可导入最新版本的mysql_async库

在rust中引入mysql_async库

在顶端加入

1
2
use mysql_async::prelude::*;
use mysql_async::Error;

初始化

初始化tokio

使用tokio宏在main函数中初始化tokio

1
2
3
4
#[tokio::main]
async fn main() -> Result<(), Error> {
// ...
}

创建mysql连接

1
2
3
4
5
6
7
8
9
10
11
// mysql连接url
let mysql_url = "mysql://user:password@host:port/database";

// 创建mysql连接池
let mysql_pool = mysql_async::Pool::new(mysql_url);

// 从mysql连接池中创建mysql连接
let mut mysql_connect = mysql_pool.get_conn().await?;

// 可以创建多个mysql连接
let mut mysql_connect_1 = mysql_pool.get_conn().await?;

由于get_conn是异步方法,所以需要使用await去推动执行

mysql查询

可以使用Trait mysql_async::prelude::QueryTrait mysql_async::prelude::Queryable进行sql查询

查询示例:

1
2
3
4
5
6
7
8
// 创建表
r"CREATE TABLE registry (
id INT NOT NULL,
name TEXT NOT NULL,
score TINYINT NOT NULL
)"
.ignore(&mut mysql_connect)
.await?;

上面示例中,使用Trait mysql_async::prelude::Queryignore方法进行sql查询,Trait Query中有impl<Q: AsQuery> Query for Q,它为满足于AsQuery Trait约束的所有类型实现了Query Trait的方法(其中包括ignore)

而在Trait AsQuery中又有impl AsQuery for &str,故&str实现了AsQuery Trait,因此可以使用ignore方法

更多实现了AsQuery Trait的类型可以参考: AsQuery

安全的sql查询

使用params!宏可以安全的将rust变量替换到sql语句中
示例:

1
2
3
4
let select_data: Option<Row> = r"SELECT name, score FROM registry WHERE id=:id"
.with(params! {"id" => num})
.first(&mut mysql_connect)
.await?;

params!宏会替换:标记的文本,使用with方法去将params!应用的查询语句中,随后再调用查询方法即可

批量sql查询

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
struct Data {
id: i32,
name: String,
score: i8,
}

let data = vec![
Data {
id: 1,
name: "张三".into(),
score: 96,
},
Data {
id: 2,
name: "李四".into(),
score: 66,
},
Data {
id: 3,
name: "王五".into(),
score: 78,
},
];

r"INSERT INTO registry (id, name, score) VALUES (:id, :name, :score)"
.with(data.iter().map(|data| {
params! {
"id" => data.id,
"name" => &data.name,
"score" => data.score
}
}))
.batch(&mut mysql_connect)
.await?;

with方法可以传入一个params!迭代器,随后调用batch方法即可批量替换sql语句进行查询


清理工作

1
2
3
4
5
6
7
8
// 关闭mysql连接
drop(mysql_connect);

// 关闭mysql连接池
mysql_pool.disconnect().await?;

// return main 退出主线程
Ok(())

完整示例代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
use mysql_async::prelude::*;
use mysql_async::Error;
use mysql_async::Row;
use mysql_async::from_value;
use std::io::{stdin,stdout,Write};

#[derive(Debug)]
struct Data {
id: i32,
name: String,
score: i8,
}

fn input<T: std::str::FromStr>(msg: &str) -> T{
print!("{}",msg);
stdout().flush().unwrap();
let mut s = String::new();
stdin().read_line( &mut s).unwrap();
match s.trim().parse::<T>() {
Ok(num) => num,
Err(_) => panic!("输入错误!")
}
}

#[tokio::main]
async fn main() -> Result<(), Error> {
let num = input::<i32>("请输入要查询的ID:");

let mysql_url = "mysql://t2:12345678@172.21.198.103:3306/t2";
let mysql_pool = mysql_async::Pool::new(mysql_url);
let mut mysql_connect = mysql_pool.get_conn().await?;
let data = vec![
Data {
id: 1,
name: "张三".into(),
score: 96,
},
Data {
id: 2,
name: "李四".into(),
score: 66,
},
Data {
id: 3,
name: "王五".into(),
score: 78,
},
];

r"CREATE TABLE registry (
id INT NOT NULL,
name TEXT NOT NULL,
score TINYINT NOT NULL
)"
.ignore(&mut mysql_connect)
.await?;

r"INSERT INTO registry (id, name, score) VALUES (:id, :name, :score)"
.with(data.iter().map(|data| {
params! {
"id" => data.id,
"name" => &data.name,
"score" => data.score
}
}))
.batch(&mut mysql_connect)
.await?;

let select_data: Option<Row> = r"SELECT name, score FROM registry WHERE id=:id"
.with(params! {"id" => num})
.first(&mut mysql_connect)
.await?;

if let Some(name) = select_data {
println!("名字为:{}, 成绩:{}", from_value::<String>(name[0].clone()), from_value::<i8>(name[1].clone()));
let score:i8 = input("请输入要更改的成绩:");
r"UPDATE registry SET score=:score WHERE id=:id".with(params! {
"score" => score,
"id" => num
}).ignore(&mut mysql_connect).await?;
println!("更改成功");
// 下面的语句用于验证是否成功更改
// let query_score: i8 = r"SELECT score FROM registry WHERE id=:id".with(params! {"id" => num}).first(&mut mysql_connect).await?.unwrap();
// assert_eq!(query_score,score);
} else {
println!("未查找到!");
}


drop(mysql_connect);
mysql_pool.disconnect().await?;

Ok(())
}
留言