rust简单操作mysql增删查改

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: rust简单操作mysql增删查改

hello_salvo中,我们已经解决了如何解析请求数据的问题。接下来我们需要解决如何通过rust对数据库进行操作的问题。我们先从最简单的增删查改开始:

依赖

[dependencies]
# 序列化工具
serde = { version = "1.0.140", features = ["derive"] }
# 一次性初始化对象工具包
once_cell = "1.13.0"
#数据库依赖
mysql = "20.0.0"
#处理时间
chrono = "0.4.19"
复制代码

当前的示例是使用rust操作mysql数据库,所以我们主要的依赖是mysql,其他的基本都是辅助性的crate。

创建表结构

我们先简单创建一个数据表来做示例:

网络异常,图片无法展示
|

构建Account结构体

我们在创建好表结构后,需要在rust项目中创建与之对应的结构体,以便后续CRUD的时候围绕这个结构体来操作数据表记录。

use chrono::NaiveDateTime;
use serde::Serialize;
#[derive(Debug, PartialEq, Eq, Clone, Serialize)]
pub struct Account {
    pub id: String,
    pub account: String,
    pub password: String,
    pub enabled: i32,
    pub create_time: NaiveDateTime,
    pub modify_time: NaiveDateTime,
}
复制代码

构建链接池

use mysql::{Pool, PooledConn};
use once_cell::sync::OnceCell;
use tracing::{instrument, info};
// 创建一个全局的DB_POOL,可以一直使用,启动的时候初始化即可
static DB_POOL: OnceCell<Pool> = OnceCell::new();
// 初始化数据库链接池
#[instrument]
pub fn init_mysql_pool(db_url: &str) {
    info!("初始化数据库线程池--------开始-------");
    DB_POOL.set(mysql::Pool::new(&db_url).expect(&format!("Error connecting to {}", &db_url)))
        .unwrap_or_else(|_| { info!("try insert pool cell failure!") });
    info!("初始化数据库线程池--------结束-------");
}
// 从链接链接池里面获取链接
#[instrument]
pub fn get_connect() -> PooledConn {
    info!("从链接池获取数据库链接----------开始----------");
    let conn = DB_POOL.get().expect("Error get pool from OneCell<Pool>").get_conn().expect("Error get_connect from db pool");
    info!("从链接池获取数据库链接----------结束----------");
    conn
}
复制代码

我们使用了OnceCell的方式构建了一个链接池,这个链接池只允许被get_connect方法使用,DB_POOL只会在项目启动的时候被初始化一次,初始化成功后,我们就可以一直调用DB_POOL获取数据库链接了。

CRUD操作

  • 查询
pub fn get_by_id(id: &str) -> Option<Account> {
        // 获取数据库链接
        let mut conn = get_connect();
        // 根据id查询账号信息
        let query_result = conn.exec_first("select id,account,password,enabled,create_time,modify_time from account where id=:id", params!("id"=>id))
            .map(|row| {
                row.map(|(id, account, password, enabled, create_time, modify_time)| Account { id, account, password, enabled, create_time, modify_time })
            });
        // 判断是否查询到数据
        match query_result {
            Ok(result) => {
                result
            }
            Err(_) => {
                None
            }
        }
    }
复制代码

1.链接池在项目启动的时候已经构建完毕,init_mysql_pool方法可以在main函数中直接调用,所以我们在数据库操作的时候可以直接调用get_connect方法获取数据库链接;

2.通过conn直接调用exec_first传递sql语句和对应的参数值;

3.返回值通过map方法解析拿到的row结果集,在里面直接构建Account对象并返回;

4.判断拿到的结果集是否有数据,有的话直接返回;报错的话,返回None;

  • 插入
pub fn insert(account: &str, password: &str) -> Result<u64, GlobalError> {
        // 获取数据库链接
        let mut conn = get_connect();
        // 生成主键id
        let id = utils::generate_id()?;
        // 执行插入语句,目前id写死,后续会修改
        let x = match "insert into account (id,account,password,enabled,create_time,modify_time) values (?,?,?,1,now(),now())"
            .with((id, account, password))
            .run(&mut conn) {
            // 返回受影响的数据行数
            Ok(res) => {
                Ok(res.affected_rows())
            }
            Err(e) => {
                Err(GlobalError::new(200, "创建账号失败", e.to_string().as_str()))
            }
        };
        x
    }
复制代码

1.现获取数据库链接;

2.准备好主键id值;这里没有使用数据库自增主键,小伙伴们可以自行使用;

3.编写sql语句,通过with方法传递参数值,里面传递元组;

4.通过run方法把数据库链接传递进去;

5.判断返回结果值;res.affected_rows()是获取受影响的行数;

pub fn delete_by_id(id: &str) -> Result<u64, GlobalError> {
        let mut conn = get_connect();
        let x = match "DELETE FROM account WHERE id=?"
            .with((id, ))
            .run(&mut conn) {
            Ok(res) => {
                Ok(res.affected_rows())
            }
            Err(e) => {
                Err(GlobalError::new(200, "删除用户失败", e.to_string().as_str()))
            }
        };
        x
    }
复制代码

1.获取数据库链接;

2.编写删除的sql语句;

3.传递参数值;需要注意的是,因为只有一个参数值,所以传递的元组需要加上逗号才能正确解析,否则报错;比如(id,)代表只有一个参数值的元组;

4.判断返回值是否正常;

pub fn update(account: Account) -> Result<u64, GlobalError> {
        let mut conn = get_connect();
        let x = match "UPDATE account SET account=?, password=?,enabled=?, modify_time=now() where id=?".with((&account.account, &account.password, &account.enabled, &account.id)).run(&mut conn) {
            Ok(res) => {
                Ok(res.affected_rows())
            }
            Err(e) => {
                Err(GlobalError::new(200, "用户信息更新失败", e.to_string().as_str()))
            }
        };
        x
    }
复制代码

1.获取数据库链接;

2.编写更新的sql语句;

3.通过with方法传递参数值,并使用run方法传递数据库链接执行sql语句;

5.判断返回值是否正常;

测试

#[cfg(test)]
mod test {
    use chrono::NaiveDateTime;
    use crate::dao::account_mapper::AccountMapper;
    use crate::dao::po::account::Account;
    use crate::dao;
    // 测试查询功能
    #[test]
    pub fn get_by_id_test() {
        // 初始化数据库链接
        dao::init();
        // 执行查询
        let res = AccountMapper::get_by_id("1");
        // 验证查询结果
        assert_eq!(res, Some(Account {
            id: String::from("1"),
            account: String::from("zouwei"),
            password: String::from("123456"),
            enabled: 1,
            create_time: NaiveDateTime::parse_from_str("2022-07-28 17:08:19", "yyyy-MM-dd HH:mm:ss").unwrap(),
            modify_time: NaiveDateTime::parse_from_str("2022-07-28 17:08:19", "yyyy-MM-dd HH:mm:ss").unwrap(),
        }));
    }
    // 测试添加账号
    #[test]
    pub fn insert_test() {
        // 初始化数据库链接池
        dao::init();
        // 添加账号
        let res = AccountMapper::insert("zouwei", "098765");
        // 校验结果
        assert_eq!(res, Ok(1));
    }
    // 测试删除功能
    #[test]
    pub fn delete_by_id_test() {
        // 初始化数据库链接
        dao::init();
        // 根据主键删除数据
        let res = AccountMapper::delete_by_id("1");
        // 验证结果
        assert_eq!(res, Ok(1));
    }
    #[test]
    pub fn update_test() {
        // 初始化数据库链接池
        dao::init();
        // 获取当前时间
        let data_time = chrono::offset::Utc::now();
        // 更新用户信息
        let res = AccountMapper::update(Account {
            id: String::from("2"),
            account: String::from("zouwei"),
            password: String::from("123456"),
            enabled: 1,
            create_time: NaiveDateTime::from_timestamp(data_time.timestamp(), 0),
            modify_time: NaiveDateTime::from_timestamp(data_time.timestamp(), 0),
        });
        // 验证结果
        assert_eq!(res, Ok(1));
    }
}
复制代码

通过以上四个测试方法,我们可以对前面编写的增删查改功能做一个简单测试,基本可以验证我们编写的代码是能正常执行的。


相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
4月前
|
SQL 运维 关系型数据库
MySQL 中 GRANT 操作会引起复制中断吗?
GRANT 操作并不是一个原子性操作,不管执行成功与否,都会触发一个隐式重载授权表的行为。 在生产环境中需要规范用户创建及授权的操作,不推荐使用 DML 语句去直接变更 mysql.user 表,可能会引发其他的问题,若使用了 DML 语句进行变更, 需要手工执行 flush privileges。
68 4
|
4月前
|
JavaScript 关系型数据库 MySQL
创建nodejs项目并接入mysql,完成用户相关的增删改查的详细操作
创建nodejs项目并接入mysql,完成用户相关的增删改查的详细操作
67 0
|
5月前
|
关系型数据库 MySQL
【mysql技巧】如何在这个mysql语句执行前加个前提,也就是只有表里没有相同数据才进行添加插入操作
【mysql技巧】如何在这个mysql语句执行前加个前提,也就是只有表里没有相同数据才进行添加插入操作
39 1
|
2月前
|
SQL Java 关系型数据库
MySQL数据库基础:增删查改
本文详细介绍了数据库中常用数据类型的使用方法及其在Java中的对应类型,并演示了如何创建表、插入数据、查询数据(包括全列查询、指定列查询、去重查询、排序查询、条件查询和分页查询)、修改数据以及删除数据。此外,还特别强调了处理NULL值时的注意事项,以及在执行修改和删除操作时应谨慎使用条件语句,以避免误操作导致的数据丢失。
77 14
MySQL数据库基础:增删查改
|
1月前
|
存储 关系型数据库 MySQL
【探究Mysql表中的增删查改(进阶篇)】
【探究Mysql表中的增删查改(进阶篇)】
54 7
|
4月前
|
存储 关系型数据库 文件存储
面试题MySQL问题之简单的SELECT操作在MVCC下加锁如何解决
面试题MySQL问题之简单的SELECT操作在MVCC下加锁如何解决
49 2
|
4月前
|
SQL 关系型数据库 MySQL
实时计算 Flink版操作报错合集之从mysql读数据写到hive报错,是什么原因
在使用实时计算Flink版过程中,可能会遇到各种错误,了解这些错误的原因及解决方法对于高效排错至关重要。针对具体问题,查看Flink的日志是关键,它们通常会提供更详细的错误信息和堆栈跟踪,有助于定位问题。此外,Flink社区文档和官方论坛也是寻求帮助的好去处。以下是一些常见的操作报错及其可能的原因与解决策略。
|
4月前
|
消息中间件 关系型数据库 MySQL
实时计算 Flink版操作报错合集之运行mysql to doris pipeline时报错,该如何排查
在使用实时计算Flink版过程中,可能会遇到各种错误,了解这些错误的原因及解决方法对于高效排错至关重要。针对具体问题,查看Flink的日志是关键,它们通常会提供更详细的错误信息和堆栈跟踪,有助于定位问题。此外,Flink社区文档和官方论坛也是寻求帮助的好去处。以下是一些常见的操作报错及其可能的原因与解决策略。
|
4月前
|
消息中间件 关系型数据库 MySQL
实时计算 Flink版操作报错合集之整库同步mysql到starRock提交任务异常,该如何处理
在使用实时计算Flink版过程中,可能会遇到各种错误,了解这些错误的原因及解决方法对于高效排错至关重要。针对具体问题,查看Flink的日志是关键,它们通常会提供更详细的错误信息和堆栈跟踪,有助于定位问题。此外,Flink社区文档和官方论坛也是寻求帮助的好去处。以下是一些常见的操作报错及其可能的原因与解决策略。
|
4月前
|
SQL 关系型数据库 MySQL
「Python入门」python操作MySQL和SqlServer
**摘要:** 了解如何使用Python的pymysql模块与MySQL数据库交互。首先,通过`pip install pymysql`安装模块。pymysql提供与MySQL的连接功能,例如创建数据库连接、执行SQL查询。在设置好MySQL环境后,使用`pymysql.connect()`建立连接,并通过游标执行SQL(如用户登录验证)。注意防止SQL注入,使用参数化查询。增删改操作需调用`conn.commit()`来保存更改。pymssql模块类似,但导入和连接对象创建略有不同。
62 0
「Python入门」python操作MySQL和SqlServer
下一篇
无影云桌面