Rust操作MySQL

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: Rust操作MySQL

查询


本部分是对「Rust入门系列」Rust 中使用 MySQL的学习与记录


  • 经常使用的时间处理库:chrono
  • 流式查询使用: query_iter
  • 输出到Vec使用:query
  • 映射到结构体使用: query_map


  • 获取单条数据使用:query_first
  • 命名参数查询使用:exec_first
CREATE TABLE `student` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(128) NOT NULL,
  `age` int(11) NOT NULL,
  `id_card` varchar(128) NOT NULL,
  `last_update` date NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- 插入测试数据
insert into student (name, age, id_card, last_update) values ('张三', 23, '123456789X', CURRENT_DATE());
insert into student (name, age, id_card, last_update) values ('李四', 24, '8382353902', CURRENT_DATE())

注意,mysql这个crate新版本demo有问题,文档的更新速度跟不上代码的修改脚步..

需要指定版本:

[dependencies]
mysql = "20.0.0" #通配符*表示可以使用任何版本,通常会拉取最新版本;此处需要指定,不使用最新版本

微信截图_20230801214434.png

流式查询

use chrono::prelude::*;// 用来处理日期
use mysql::*;
use mysql::prelude::*;
fn main() {
    let url = "mysql://root:12345678@localhost:3306/shuang";
    let pool = Pool::new(url).unwrap(); // 获取连接池
    let mut conn = pool.get_conn().unwrap();// 获取链接
    conn.query_iter("select * from student")
        .unwrap()
        .for_each(|row| {
            let r: (i32, String, i32, String, NaiveDate) = from_row(row.unwrap());
            println!("{}, {},{},{}, {:?}", r.0, r.1, r.2, r.3, r.4);
        });
}

row的类型是mysql_common::row::Row,其把数据以字节的形式存储。

所以需将低级的字节转换成想要的类型 如i32,String,这里使用了from_row。注意,转换后的数据以元组的形式返回,其中每一项和选择列的顺序相同。


输出:

1, 张三,23,123456789X, 2022-04-26
2, 李四,24,8382353902, 2022-04-26

流式查询


其实还可以将查询结果收集到Vec中。 Vec中的每个元素都是一个元组。

query函数已经将字节转换为选择的数据类型,因此不需要再转换了。 需要注意的是,这里必须明确元组的数据类型(如此处是 Vec<(i32, String, i32, String, NaiveDate)>)。 否则,编译器没办法做转换。

use chrono::prelude::*;// 用来处理日期
use mysql::*;
use mysql::prelude::*;
fn main() {
    let url = "mysql://root:12345678@localhost:3306/shuang";
    let pool = Pool::new(url).unwrap(); // 获取连接池
    let mut conn = pool.get_conn().unwrap();// 获取链接
// 输出到Vec
    let res: Vec<(i32, String, i32, String, NaiveDate)> =
        conn.query("select * from student").unwrap();
    for r in res {
        println!("{}, {},{},{}, {:?}", r.0, r.1, r.2, r.3, r.4);
    }
}

映射结果到结构体


如果表的列数很多,使用元组容易混淆,更普遍的做法是定义一个结构体。

如下定义一个Student结构体, 然后可以用query_map将查询结果映射到Student中。

不需要指定数据类型,编译器会根据Student类型自动推导

use chrono::prelude::*;// 用来处理日期
use mysql::*;
use mysql::prelude::*;
fn main() {
    let url = "mysql://root:12345678@localhost:3306/shuang";
    let pool = Pool::new(url).unwrap(); // 获取连接池
    let mut conn = pool.get_conn().unwrap();// 获取链接
    // 将结果映射到提前定义好的结构体
    struct Student {
        id: u64,
        name: String,
        age: u16,
        id_card: String,
        last_changed_on: NaiveDate,
    }
    let res = conn.query_map(
        "select * from student",
        |(id, name, age, id_card, update)| Student {
            id: id,
            name: name,
            age: age,
            id_card: id_card,
            last_changed_on: update,
        },
    ).expect("Query failed.");
    for i in res {
        println!(
            "{}, {},{},{}, {:?}",
            i.id, i.name, i.age, i.id_card, i.last_changed_on
        )
    }
}

单条数据查询


查询特定数据行,可能会出现下面几种情况:

  • 找到,返回实际数据
  • 没有找到行
  • 发生错误

所以,使用query_first函数返回的是Option的结果。 需要将其解包两次才可以获取实际的行数据:

use chrono::prelude::*;// 用来处理日期
use mysql::*;
use mysql::prelude::*;
fn main() {
    let url = "mysql://root:12345678@localhost:3306/shuang";
    let pool = Pool::new(url).unwrap(); // 获取连接池
    let mut conn = pool.get_conn().unwrap();// 获取链接
    struct Student {
        id: u64,
        name: String,
        age: u16,
        id_card: String,
        last_changed_on: NaiveDate,
    }
    // 条件查询,查询单个数据
    let res = conn.query_first("select * from student where name = '张三'")
        .map(
            // Unpack Result
            |row| {
                row.map(|(id, name, age, id_card, update)| Student {
                    id: id,
                    name: name,
                    age: age,
                    id_card: id_card,
                    last_changed_on: update,
                })
            },
        );
    match res.unwrap() {
        Some(student) => println!(
            "{}, {},{},{}, {:?}",
            student.id, student.name, student.age, student.id_card, student.last_changed_on
        ),
        None => println!("Sorry no student found."),
    }
}

命名参数的使用

use chrono::prelude::*;// 用来处理日期
use mysql::*;
use mysql::prelude::*;
fn main() {
    let url = "mysql://root:12345678@localhost:3306/shuang";
    let pool = Pool::new(url).unwrap(); // 获取连接池
    let mut conn = pool.get_conn().unwrap();// 获取链接
    struct Student {
        id: u64,
        name: String,
        age: u16,
        id_card: String,
        last_changed_on: NaiveDate,
    }
    let res = conn
        .exec_first(
            "select * from student where name = :name",
            params! {
                "name" => "李四"
            },
        )
        .map(
            // Unpack Result
            |row| {
                row.map(|(id, name, age, id_card, update)| Student {
                    id: id,
                    name: name,
                    age: age,
                    id_card: id_card,
                    last_changed_on: update,
                })
            },
        );
    match res.unwrap() {
        Some(student) => println!(
            "{}, {},{},{}, {:?}",
            student.id, student.name, student.age, student.id_card, student.last_changed_on
        ),
        None => println!("Sorry no student found."),
    }
}

写操作


本部分是对Rust使用MySQL数据库02的学习与记录

  • 插入数据使用conn.exec_drop()
  • 使用预编译语句插入大量数据,conn.prep()
  • 使用conn.last_insert_id()可以获取主键


  • 更新和删除也使用conn.prepconn.exec_drop


插入新数据

use chrono::prelude::*;
// 用来处理日期
use mysql::*;
use mysql::prelude::*;
fn main() {
    let url = "mysql://root:12345678@localhost:3306/shuang";
    let pool = Pool::new(url).unwrap(); // 获取连接池
    let mut conn = pool.get_conn().unwrap();// 获取链接
    conn.exec_drop(
        "INSERT INTO student (name, age, id_card, last_update) VALUES (:name, :age, :id_card, :last_update)",
        params! {
        "name" => "王五",
        "age" => 28,
        "id_card" => "66666688",
        "last_update" => today(),
}).unwrap();
}
fn today() -> NaiveDate {
    let l = Local::today();
    NaiveDate::from_ymd(l.year(), l.month(), l.day())
}

微信截图_20230801214646.png

和上面一节一样,命名参数在这里使用了params宏的语法


exec_drop方法中的drop表示没有返回结果

用于执行插入/更新/删除的sql


使用预编译语句


使用conn.prep将sql编译成预编译语句。

use chrono::prelude::*;
// 用来处理日期
use mysql::*;
use mysql::prelude::*;
fn main() {
    let url = "mysql://root:12345678@localhost:3306/shuang";
    let pool = Pool::new(url).unwrap(); // 获取连接池
    let mut conn = pool.get_conn().unwrap();// 获取链接
    let stmt = conn.prep("INSERT INTO student (name, age, id_card, last_update) VALUES (:name, :age, :id_card, :last_update)")
        .unwrap();
    for i in 1..10 {
        conn.exec_drop(&stmt, params! {
         "name" => "dashen",
         "age" => 18 + i,
         "id_card" => "1234565X",
         "last_update" => NaiveDate::from_ymd(2017, 05, 04),
     }).unwrap()
    }
}

微信截图_20230801214728.png

获取生成的主键id


可以通过conn.last_insert_id()方法获取到新记录的主键id,该方法将返回的一个类型为u64 的值

use chrono::prelude::*;
// 用来处理日期
use mysql::*;
use mysql::prelude::*;
fn main() {
    let url = "mysql://root:12345678@localhost:3306/shuang";
    let pool = Pool::new(url).unwrap(); // 获取连接池
    let mut conn = pool.get_conn().unwrap();// 获取链接
    conn.exec_drop("INSERT INTO student (name, age, id_card, last_update) VALUES (:name, :age, :id_card, :last_update)", params! {
    "name" => "fliter",
    "age" => 29,
    "id_card" => "88888888",
    "last_update" => NaiveDate::from_ymd(2022, 05, 04),
}).unwrap();
    println!("新插入的记录的主键为: {}", conn.last_insert_id())
}
新插入的记录的主键为: 13

微信截图_20230801214818.png

更新和删除


类似于插入操作

use chrono::prelude::*;
// 用来处理日期
use mysql::*;
use mysql::prelude::*;
fn main() {
    let url = "mysql://root:12345678@localhost:3306/shuang";
    let pool = Pool::new(url).unwrap(); // 获取连接池
    let mut conn = pool.get_conn().unwrap();// 获取链接
    let stmt = conn.prep("update student set name=:name, last_update=:last_update where id=:id")
        .unwrap();
    conn.exec_drop(&stmt, params! {
     "name" => "新名字",
     "last_update" => NaiveDate::from_ymd(2038, 12, 31),
     "id" => 10,
}).unwrap();
    let stmt = conn.prep("delete from student where id=:id").unwrap();
    conn.exec_drop(&stmt, params! {
    "id" => 12,
}).unwrap();
}

微信截图_20230801214902.png

相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
5天前
|
SQL 关系型数据库 MySQL
python操作mysql
python操作mysql
|
5天前
|
安全 关系型数据库 MySQL
轻松入门MySQL:MySQL8权限管理详解,角色和用户操作实例(18)
轻松入门MySQL:MySQL8权限管理详解,角色和用户操作实例(18)
104 0
|
5天前
|
存储 SQL 关系型数据库
【MySQL】4. 表的操作
【MySQL】4. 表的操作
26 0
|
5天前
|
缓存 关系型数据库 MySQL
MySQL查询优化:提速查询效率的13大秘籍(合理使用索引合并、优化配置参数、使用分区优化性能、避免不必要的排序和group by操作)(下)
MySQL查询优化:提速查询效率的13大秘籍(合理使用索引合并、优化配置参数、使用分区优化性能、避免不必要的排序和group by操作)(下)
|
1天前
|
Oracle 关系型数据库 MySQL
实时计算 Flink版操作报错合集之用CTAS从mysql同步数据到hologres,改了字段长度,报错提示需要全部重新同步如何解决
在使用实时计算Flink版过程中,可能会遇到各种错误,了解这些错误的原因及解决方法对于高效排错至关重要。针对具体问题,查看Flink的日志是关键,它们通常会提供更详细的错误信息和堆栈跟踪,有助于定位问题。此外,Flink社区文档和官方论坛也是寻求帮助的好去处。以下是一些常见的操作报错及其可能的原因与解决策略。
38 8
|
2天前
|
SQL 关系型数据库 MySQL
实时计算 Flink版操作报错合集之程序初始化mysql没有完成就报错如何解决
在使用实时计算Flink版过程中,可能会遇到各种错误,了解这些错误的原因及解决方法对于高效排错至关重要。针对具体问题,查看Flink的日志是关键,它们通常会提供更详细的错误信息和堆栈跟踪,有助于定位问题。此外,Flink社区文档和官方论坛也是寻求帮助的好去处。以下是一些常见的操作报错及其可能的原因与解决策略。
12 4
|
2天前
|
关系型数据库 MySQL 数据库
实时计算 Flink版操作报错合集之sqlserver mysql都用的胖包,sqlserver的成功了,mysql报这个错如何解决
在使用实时计算Flink版过程中,可能会遇到各种错误,了解这些错误的原因及解决方法对于高效排错至关重要。针对具体问题,查看Flink的日志是关键,它们通常会提供更详细的错误信息和堆栈跟踪,有助于定位问题。此外,Flink社区文档和官方论坛也是寻求帮助的好去处。以下是一些常见的操作报错及其可能的原因与解决策略。
16 6
|
2天前
|
SQL Oracle 关系型数据库
实时计算 Flink版操作报错合集之连接器换成2.4.2之后,mysql作业一直报错如何解决
在使用实时计算Flink版过程中,可能会遇到各种错误,了解这些错误的原因及解决方法对于高效排错至关重要。针对具体问题,查看Flink的日志是关键,它们通常会提供更详细的错误信息和堆栈跟踪,有助于定位问题。此外,Flink社区文档和官方论坛也是寻求帮助的好去处。以下是一些常见的操作报错及其可能的原因与解决策略。
12 3
|
4天前
|
SQL 关系型数据库 MySQL
Mysql忘记密码操作
Mysql忘记密码操作
22 1
|
5天前
|
SQL 关系型数据库 MySQL
DQL操作MySql
DQL操作MySql
12 0

推荐镜像

更多