Rust操作MySQL

news/2024/5/13 15:28:04

查询


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


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

  • 获取单条数据使用: query_first
  • 命名参数查询使用: exec_first
CREATE TABLE `student` (
  `id` int(11NOT NULL AUTO_INCREMENT,
  `name` varchar(128NOT NULL,
  `age` int(11NOT NULL,
  `id_card` varchar(128NOT 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[2]这个crate新版本demo有问题,文档的更新速度跟不上代码的修改脚步..

需要指定版本:

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

流式查询


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: (i32Stringi32String, 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,83823539022022-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<(i32Stringi32String, 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[3]的学习与记录

  • 插入数据使用 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())
}

alt

和上面一节一样,命名参数在这里使用了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(20170504),
     }).unwrap()
    }
}
alt

获取生成的主键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(20220504),
}).unwrap();

    println!("新插入的记录的主键为: {}", conn.last_insert_id())
}

新插入的记录的主键为: 13
alt

更新和删除


类似于插入操作

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(20381231),
     "id" => 10,
}).unwrap();


    let stmt = conn.prep("delete from student where id=:id").unwrap();

    conn.exec_drop(&stmt, params! {
    "id" => 12,
}).unwrap();
}
alt

参考资料

[1]

「Rust入门系列」Rust 中使用 MySQL: https://rustmagazine.github.io/rust_magazine_2021/chapter_3/rust-mysql.html

[2]

mysql: https://crates.io/crates/mysql

[3]

Rust使用MySQL数据库02: https://www.modb.pro/db/179746

本文由 mdnice 多平台发布


http://www.mrgr.cn/p/55164173

相关文章

消息队列——rabbitmq的不同工作模式

目录 Work queues 工作队列模式 Pub/Sub 订阅模式 Routing路由模式 Topics通配符模式 工作模式总结 Work queues 工作队列模式 C1和C2属于竞争关系&#xff0c;一个消息只有一个消费者可以取到。 代码部分只需要用两个消费者进程监听同一个队里即可。 两个消费者呈现竞争关…

【机器学习】了解 AUC - ROC 曲线

一、说明 在机器学习中&#xff0c;性能测量是一项基本任务。因此&#xff0c;当涉及到分类问题时&#xff0c;我们可以依靠AUC - ROC曲线。当我们需要检查或可视化多类分类问题的性能时&#xff0c;我们使用AUC&#xff08;曲线下面积&#xff09;ROC&#xff08;接收器工作特…

(八九)如何与InfluxDB交互InfluxDB HTTP API

以下内容来自 尚硅谷&#xff0c;写这一系列的文章&#xff0c;主要是为了方便后续自己的查看&#xff0c;不用带着个PDF找来找去的&#xff0c;太麻烦&#xff01; 第 8 章 前言&#xff1a;如何与InfluxDB交互 1、InfluxDB启动后&#xff0c;会向外提供一套HTTP API。外部程…

【机器学习】Feature Engineering and Polynomial Regression

Feature Engineering and Polynomial Regression 1. 多项式特征2. 选择特征3. 缩放特征4. 复杂函数附录 首先&#xff0c;导入所需的库&#xff1a; import numpy as np import matplotlib.pyplot as plt from lab_utils_multi import zscore_normalize_features, run_gradien…

级联选择框

文章目录 实现级联选择框效果图实现前端工具版本添加依赖main.js导入依赖级联选择框样式 后端数据库设计 实现级联选择框 效果图 实现 前端 工具版本 node.js v16.6.0vue3 级联选择框使用 Element-Plus 实现 添加依赖 在 package.json 添加依赖&#xff0c;并 npm i 导入…

YouIcons-矢量图标、LOGO和插图素材下载 48000000+

YouIcons是一个免费下载矢量图标、LOGO和插图素材下的网站&#xff0c;图标量高达千万级别&#xff0c;目前共收录48109736个&#xff0c;是世界领先的创意徽标logo社区&#xff0c;供创意人员下载、分享、成长和使用&#xff0c;是设计师获取灵感、发现并与全球设计师联系的社…

PostgreSQL构建时间

– PostgreSQL构建时间 select make_timestamp(2023,7,27,7,34,16);

C#——多线程之Task

C#——多线程之Task 前言一、Task是什么&#xff1f;二、各应用场景以及实例分析1.异步执行代码2.等待异步操作完成3.并行执行多个任务4.处理异常5.取消异步操作 三、一些其他问题1.WhenAll与WhenAny的区别 总结 前言 在代码编写过程中&#xff0c;经常会用到多线程的知识&…

三子棋(超详解+完整码源)

三子棋 前言一&#xff0c;游戏规则二&#xff0c;所需文件三&#xff0c;创建菜单四&#xff0c;游戏核心内容实现1.棋盘初始化1.棋盘展示3.玩家下棋4.电脑下棋5.游戏胜负判断6.game&#xff08;&#xff09;函数内部具体实现 四&#xff0c;游戏运行实操 前言 C语言实现三子棋…

volley 学习笔记1--发送请求

一、概览 Volley 具有以下优势&#xff1a; 自动网络请求调度。 多个并发网络连接。 透明磁盘和具有标准 HTTP 缓存一致性的内存响应缓存。 支持请求优先级。 取消请求 API。您可以取消单个请求&#xff0c;也可以设置要取消的请求的时间段或范围。 可轻松自定义&#xff…

手机快充协议

高通:QC2.0、QC3.0、QC3.5、QC4.0、QC5.0、 FCP、SCP、AFC、SFCP、 MTKPE1.1/PE2.0/PE3.0、TYPEC、PD2.0、PD3.0/3.1、VOOC 支持 PD3.0/PD2.0 支持 QC3.0/QC2.0 支持 AFC 支持 FCP 支持 PE2.0/PE1.1 联发科的PE&#xff08;Pump Express&#xff09;/PE 支持 SFCP 在PP…

Stable Diffusion如何生成高质量的图-prompt写法介绍

文章目录 Stable Diffusion使用尝试下效果prompt的编写技巧prompt 和 negative promptPrompt格式Prompt规则细节优化Guidance Scale 总结 Stable Diffusion Stable Diffusion是一个开源的图像生成AI系统,由Anthropic公司开发。它基于 Transformer模型架构,可以通过文字描述生成…

学习笔记|大模型优质Prompt开发与应用课(二)|第五节:只需3步,优质Prompt秒变应用软件

原作者&#xff1a;依依│百度飞桨产品经理 一乔│飞桨开发者技术专家 分享内容 01:大模型应用简介 02:LLM应用开发范式 03: Al Studio大模型社区 04:AI对话类应用开发技巧 大模型技术爆发&#xff0c;各类应用产品涌现 文心产业级知识增强大模型 工作中的“超级助手”—…

一文谈谈Git

"And if forever lasts till now Alright" 为什么要有git&#xff1f; 想象一下&#xff0c;现如今你的老师同时叫你和张三&#xff0c;各自写一份下半年的学习计划交给他。 可是你的老师是一个极其"较真"的人&#xff0c;发现你俩写的学习计划太"水&…

MySQL5.7 与 MariaDB10.1 审计插件兼容性验证

这是一篇关于发现 MariaDB 审计插件导致 MySQL 发生 crash 后&#xff0c;展开适配验证并进行故障处理的文章。 作者&#xff1a;官永强 爱可生DBA 团队成员&#xff0c;擅长 MySQL 运维方面的技能。热爱学习新知识&#xff0c;亦是个爱打游戏的宅男。 本文来源&#xff1a;原创…

简单认识redis高可用实现方法

文章目录 一、redis群集三种模式二、 Redis 主从复制1、简介2、作用&#xff1a;3、流程&#xff1a;4.配置主从复制 三、Redis 哨兵模式1、简介2、原理:3、作用&#xff1a;4、哨兵结构由两部分组成&#xff0c;哨兵节点和数据节点&#xff1a;5、故障转移机制&#xff1a;6、…

软件外包开发的后台开发语言

在软件外包开发中&#xff0c;后台语言的选择通常取决于项目需求、客户偏好、团队技能和开发效率。今天和大家分享一些常用的后台语言及选择它们的原因&#xff0c;希望对大家有所帮助。北京木奇移动技术有限公司&#xff0c;专业的软件外包开发公司&#xff0c;欢迎交流合作。…

【利诱和强制分享下载】规则修改指引

代码审核环节&#xff0c;将会对小程序运营的内容进行核实是否存在阻断功能&#xff0c;损害用户体验。 常见利诱诱导类型&#xff1a; 1、利诱下载APP 小程序内出现不断弹窗、频繁提示诱导用户下载APP&#xff0c;强制用户必须下载APP才能体验完整功能服务。 示例&#xf…

数字化时代,如何做好用户体验与应用性能管理

引言 随着数字化时代的到来&#xff0c;各个行业的应用系统从传统私有化部署逐渐转向公有云、行业云、微服务&#xff0c;这种变迁给运维部门和应用部门均带来了较大的挑战。基于当前企业 IT 运维均为多部门负责&#xff0c;且使用多种运维工具&#xff0c;因此&#xff0c;当…

【Spring】Spring 中事务的实现

事务定义&#xff1a;将⼀组操作封装成⼀个执⾏单元&#xff08;封装到⼀起&#xff09;&#xff0c;要么全部成功&#xff0c;要么全部失败 Spring 中的事务操作分为两类&#xff1a; 编程式事务&#xff08;⼿动写代码操作事务&#xff09;。声明式事务&#xff08;利⽤注解…