Rust操作MySQL
查询
本部分是对 「Rust入门系列」Rust 中使用 MySQL[1]的学习与记录
-
经常使用的时间处理库: 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[2]这个crate新版本demo有问题,文档的更新速度跟不上代码的修改脚步..
需要指定版本:
[dependencies]
mysql = "20.0.0" #通配符*表示可以使用任何版本,通常会拉取最新版本;此处需要指定,不使用最新版本

流式查询
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[3]的学习与记录
-
插入数据使用 conn.exec_drop()
-
使用预编译语句插入大量数据, conn.prep()
-
使用 conn.last_insert_id()
可以获取主键
-
更新和删除也使用 conn.prep
和conn.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())
}

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

获取生成的主键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

更新和删除
类似于插入操作
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();
}

参考资料
「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 多平台发布
相关文章:

Rust操作MySQL
查询 本部分是对 「Rust入门系列」Rust 中使用 MySQL[1]的学习与记录 经常使用的时间处理库: chrono 流式查询使用: query_iter 输出到Vec使用: query 映射到结构体使用: query_map 获取单条数据使用: query_first 命名…...

JAVA面试总结-Redis篇章(二)——缓存击穿
JAVA面试总结-Redis篇章(二) 缓存击穿解决方案一:互斥锁解决方案二:逻辑过期 缓存击穿 解决方案一:互斥锁 解决方案二&…...

Spring相关知识点
概述 分层的轻量级的全栈开源框架 展示层SprigMVC 持久层 Spring JDBCTemplate 业务层事务管理 注: 轻量级:API简单 全栈:各层都有相应解决方案 在Spring的体系结构中,由上而下,逐层依赖 Spring相当于是一个粘合剂&…...

Nginx专题--反向代理(未完成)
反向代理 正向代理:如果把局域网外的 Internet 想象成一个巨大的资源库,则局域网中的客户端要访问 Internet,则需要通过代理服务器来访问,这种代理服务就称为正向代理。 反向代理:其实客户端对代理是无感知的&…...

什么是搜索引擎?2023 年搜索引擎如何运作?
目录 什么是搜索引擎?搜索引擎的原理什么是搜索引擎爬取?什么是搜索引擎索引?什么是搜索引擎检索?什么是搜索引擎排序? 搜索引擎的目的是什么?搜索引擎如何赚钱?搜索引擎如何建立索引?网页抓取文本处理建…...

Spring系列一:spring的安装与使用
文章目录 💞 官方资料🍊Spring5下载🍊文档介绍 💞Spring5🍊内容介绍🍊重要概念 💞快速入门🍊Spring操作演示🍊类加载路径🍊Debug配置🍊Spring容器…...

Ubuntu--科研工具系列
翻译系列 pot-desktop github链接: https://github.com/pot-app/pot-desktop 下载deb Releases pot-app/pot-desktop GitHub 安装过程 在下载好的deb目录下打开终端(自动安装依赖) sudo apt install "XXX.deb" (后面可以直接托文件到终端&#…...

【压测指南|压力测试核心性能指标及行业标准】
文章目录 压力测试核心性能指标及行业标准指标1:响应时间指标2:吞吐量(TPS)指标3:失败率总结: 压力测试核心性能指标及行业标准 在做压力测试时,新手测试人员常常在看报告时倍感压力:这么多性能…...

spark-submit --files
一、原理 spark-submit --files通常用来加载外部资源文件,在driver和executor进程中进行访问 –files和–jars基本相同 二、使用步骤 2.1 添加文件 spark-submit --files file_paths 其中file_paths可为多种方式:file: | hdfs:// | http:// | ftp:// |…...

应该选云服务器还是物理服务器
应该选云服务器还是物理服务器 一、为什么需要云服务器或独立服务器取代共享主机 在最早之前,大多数的网站都是共享主机开始的,这里也包含了云虚拟机。这一类的站点还有其他站点都会共同托管在同一台服务器上。但是这种共享机只适用于小的网站ÿ…...

【iOS】动态链接器dyld
参考:认识 dyld :动态链接器 dyld简介 dyld(Dynamic Linker)是 macOS 和 iOS 系统中的动态链接器,它是负责在运行时加载和链接动态共享库(dylib)或可执行文件的组件。在 macOS 系统中…...

RocketMQ集成Springboot --Chapter1
RocketMQ集成Springboot 三种消息发送方式 生产者 引入依赖 <!--⽗⼯程--><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.3.2.RELEASE</version><…...

【Unity3D日常开发】Unity3D中比较string字符串的常用方法
推荐阅读 CSDN主页GitHub开源地址Unity3D插件分享简书地址我的个人博客 大家好,我是佛系工程师☆恬静的小魔龙☆,不定时更新Unity开发技巧,觉得有用记得一键三连哦。 一、前言 字符串string的比较有很多方法,比如: …...

vue3+ts+element-plus 之使用node.js对接mysql进行表格数据展示
vue3tselement-plus axiosnode.jsmysql开发管理系统之表格展示 ✏️ 1. 新建一个node项目* 初始化node* 安装可能用到的依赖* 配置文件目录* 添加路由router1. 添加router.js文件,添加一个test目录2. 修改app.js ,引入router📒 3. 启动并在浏览器打开 * …...

华为eNSP:isis配置跨区域路由
一、拓扑图 二、路由器的配置 1、配置接口IP AR1: <Huawei>system-view [Huawei]int g0/0/0 [Huawei-GigabitEthernet0/0/0]ip add 1.1.1.1 24 [Huawei-GigabitEthernet0/0/0]q AR2: [Huawei]int g0/0/0 [Huawei-GigabitEthernet0/0/0]ip add 1.1.1.2 24 [Huawe…...

IUPAC和SMILES的相互转换
这种方法只能解决非常简单的转换,更难的SMILES之间应该是无法直接转换,我可能很多人都使用神经网络解决 ,暂时还没仔细看,后面再仔细看吧... 简单的转换: import urllib.error import urllib.parse import urllib.re…...

逻辑回归概述
逻辑回归介绍 1. 逻辑回归的应用场景 逻辑回归(Logistic Regression)是机器学习中的 一种分类模型 ,逻辑回归是一种分类算法,虽然名字中带有回归。由于算法的简单和高效,在实际中应用非常广泛 广告点击率是否为垃圾邮件是否患病信用卡账单是否会违约 逻辑回归就是解决二…...

React 框架下自己写一个braft编辑器,然后将编辑器内容展示在网页端
1.首先自己写一个编辑器 输入文字; 支持选择表情; 可添加小程序链接;可添加网页链接;并且可以编辑删除;效果如下 2.输入完毕后,点击文本输入框保存,将便携式内容回显, 渲染时…...

基于DNN深度学习网络的OFDM+QPSK信号检测算法matlab仿真
目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 matlab2022a 3.部分核心程序 ............................................................................. Transmitt…...

学生管理系统-05封装选项卡
一、选项卡的添加 1、在router/index.js修改之前的动态添加二级路由的代码 router.addRoute("homeName",{ path:routeObj.path, component:()=>import(`@/views${routeObj.permission}.vue`), meta:{ name:routeObj.title …...

关于一些C++、Qt、Python方面的术语
杂鱼之前纯粹用python没细致理解过的术语整理一下,常看常新( 定义 (Definition): 定义是指给一个实体分配内存空间,以便在程序中使用。在C和Python中,这个实体可以是变量、函数或类。在C中,定义通常是在声…...

k8s中强制删除pv
K8s 集群内有一个已经不再使用的 PV,虽然已经删除了与其关联的 Pod 及 PVC,并对其执行了删除命令,但仍无法正常删除,一直处于 Terminating 状态: 解决办法: 1. 获取pv信息 kubectl get pv 2. 解除pv锁定 …...

60寸透明屏的透明度怎么样?
60寸透明屏是一种新型的显示屏技术,它具有透明度高、色彩鲜艳、清晰度高等特点,可以广泛应用于商业展示、户外广告、智能家居等领域。 首先,60寸透明屏的透明度高。 透明屏采用了特殊的材料和技术,使得屏幕在显示内容的同时&…...

Python:使用openpyxl读取Excel文件转为json数据
文档 https://openpyxl.readthedocs.io/en/stable/https://pypi.org/project/openpyxl/ 安装 pip install openpyxl环境 $ python --version Python 3.7.0读取文件示例:将Excel文件读取为json数据 有如下一个文件 data.xlsx 实现代码 # -*- coding: utf-8 -…...

在Microsoft Excel中如何快速合并表格
在 Excel 中分析数据时,在一个工作表中收集所有必要信息的频率是多少?几乎从来没有!当不同的数据分散在许多工作表和工作簿中时,这是一种非常常见的情况。幸运的是,有几种不同的方法可以将多个表中的数据组合成一个表&…...

【RS】基于规则的面向对象分类
ENVI使用最多的工具就是分类,这也是很多卫星影像的用途。在ENVI中有很多分类工具,如最基础的监督分类(最大似然法、最小距离、支持向量机、随机森林)、非监督分类(K-means、IsoData),还有面向对…...

SWF格式视频怎么转换成AVI格式?简单的转换方法分享
当你想要在不同的设备上播放视频时,将SWF格式视频转换成AVI格式是非常有用的。因为SWF格式通常只能在特定的软件或网页上播放,而AVI格式则可以在更广泛的设备上播放,包括智能手机,平板电脑和电视机等。那么我们怎么将SWF转换成AVI…...

Hive数据仓库
数据仓库概念与起源发展由来 数仓概念 数据仓库(英语:Data Warehouse,简称数仓、DW),是一个用于存储、分析、报告的数据系统。数据仓库的目的是构建面相分析的集成化数据环境,分析结果为企业提供决策支持…...

公网访问的Linux CentOS本地Web站点搭建指南
文章目录 前言1. 本地搭建web站点2. 测试局域网访问3. 公开本地web网站3.1 安装cpolar内网穿透3.2 创建http隧道,指向本地80端口3.3 配置后台服务 4. 配置固定二级子域名5. 测试使用固定二级子域名访问本地web站点 前言 在web项目中,部署的web站点需要被外部访问,则…...

ChatGPT:人机交互新境界,AI智能引领未来
一、ChatGPT:智能交流的新标杆 ChatGPT是基于GPT技术的最新版本,拥有深度学习模型的基因。它通过在大量数据上进行预训练,可以理解和生成自然语言,从而实现了与人类更加自然流畅的对话和交流。 二、ChatGPT的技术背景和工作原理 …...