【从零开始的rust web开发之路 三】orm框架sea-orm入门使用教程

【从零开始的rust web开发之路 三】orm框架sea-orm入门使用教程


文章目录

  • 前言
  • 一、引入依赖
  • 二、创建数据库连接
    • 简单链接
    • 连接选项
    • 开启日志调试
  • 三、生成实体
    • 安装sea-orm-cli
    • 创建数据库表
    • 使用sea-orm-cli命令生成实体文件代码
  • 四、增删改查实现
    • 新增数据
    • 主键查找
    • 条件查找
      • 查找用户名是admin的一条用户
      • 查找地址是郑州的所有用户
      • 查找地址是郑州并且用户名包含admin的所有用户
      • 分页查找
    • 修改数据
    • 删除数据
    • 数据库事务操作
  • 总结

前言

前两篇文件主要降了axum相关使用,这篇文章来讲讲orm相关框架。目前rust orm相关框架不多,比较主流的是sqlx,本文介绍的框架实在此基础上封装的一层,sql-orm同样也支持rust异步。

一、引入依赖

sea-orm = { version = "0.12", features = [ <DATABASE_DRIVER>, <ASYNC_RUNTIME>, "macros" ] }  #DATABASE_DRIVERASYNC_RUNTIME参数需要替换

DATABASE_DRIVER参数

  • sqlx-mysql-SQLx的MySQL
  • sqlx-postgres-SQLx
  • PostgreSQL的 sqlx-sqlite

ASYNC_RUNTIME参数

  • runtime-async-std-native-tls
  • runtime-tokio-native-tls
  • runtime-async-std-rustls
  • runtime-tokio-rustls
    这里我们选择引入tokio异步支持的,还要引入tokio
[dependencies]
sea-orm = { version = "0.12", features = [ "sqlx-mysql", "runtime-tokio-native-tls", "macros" ] }
tokio = { version = "1.35.1", features = ["full"] }

二、创建数据库连接

简单链接

let db: DatabaseConnection = Database::connect("protocol://username:password@host/database").await?;

举例子mysql数据库连接

   let db: DatabaseConnection = Database::connect("mysql://root:root@127.0.0.1:3307/test").await.unwrap();

后续查询选相关操作每次调用DatabaseConnection ,都会从池中获取和释放连接。
连接别的数据库可以看官方文档https://www.sea-ql.org/SeaORM/docs/next/install-and-config/connection/

连接选项

若要配置连接,请使用 ConnectOptions 接口
let mut opt = ConnectOptions::new("mysql://root:root@127.0.0.1:3307/test");
opt.max_connections(100)
    .min_connections(5)
    .connect_timeout(Duration::from_secs(8))
    .acquire_timeout(Duration::from_secs(8))
    .idle_timeout(Duration::from_secs(8))
    .max_lifetime(Duration::from_secs(8))
    .sqlx_logging(true)
    .sqlx_logging_level(log::LevelFilter::Info)
    .set_schema_search_path("my_schema"); // Setting default PostgreSQL schema

let db = Database::connect(opt).await?;

可以看ConnectOptions接口文档https://docs.rs/sea-orm/0.12.12/sea_orm/struct.ConnectOptions.html

开启日志调试

开发阶段需要打印相关日志,可以开启调试模式
features当中多一个[“debug-print”]

[dependencies]
sea-orm = { version = "0.12", features = [ "sqlx-mysql", "runtime-tokio-native-tls", "macros" ,"debug-print","with-chrono"] }
tokio = { version = "1.35.1", features = ["full"] }
chrono = "0.4.33"
tracing = "0.1.40"
tracing-subscriber = { version = "0.3.18",features = [
    "env-filter",
    "time",
    "local-time", ]}

然后需要执行一段初始化tracing-subscriber代码

    // 设置全局日志级别为 info
    let env_filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info"))
        //单独设置sea_orm
        .add_directive("sea_orm::driver=debug".parse().unwrap())
        //关闭sqlx自带的日志
        .add_directive("sqlx::query=off".parse().unwrap());

三、生成实体

安装sea-orm-cli

运行命令

cargo install sea-orm-cli

创建数据库表

CREATE TABLE `user` (
  `id` int NOT NULL AUTO_INCREMENT,
  `username` varchar(32) NOT NULL COMMENT '用户名称',
  `birthday` datetime DEFAULT NULL COMMENT '生日',
  `sex` char(1) DEFAULT NULL COMMENT '性别',
  `address` varchar(256) DEFAULT NULL COMMENT '地址',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=49 DEFAULT CHARSET=utf8mb3

使用sea-orm-cli命令生成实体文件代码

在项目文件夹下运行命令,-o 是输出文件目录。相关参数配置可看文档https://www.sea-ql.org/SeaORM/docs/next/generate-entity/sea-orm-cli/

sea-orm-cli generate entity -u mysql://root:root@127.0.0.1:3307/test -o src/entity

在这里插入图片描述
在main文件加入entity模块即可。
生成的文件内容
在这里插入图片描述

在这里插入图片描述
指定表名

#[sea_orm(table_name = "cake", schema_name = "public")]
pub struct Model { ... }

指定列名

#[sea_orm(column_name = "name")]
pub name: String

四、增删改查实现

新增数据

先了解ActiveValue和ActiveModel
use entity::user::ActiveModel as UserModel;
let user: UserModel =  UserModel{
        id: ActiveValue::NotSet,
        username: ActiveValue::Set("你好".to_owned()),
        birthday: ActiveValue::Set(Some(Local::now().naive_local())),
        sex: ActiveValue::Set(Some("1".to_owned())),
        address: ActiveValue::Set(Some("address".to_owned())),
    };

这里我们创建UserModel的ActiveModel模型,里面的值是ActiveValue类型,NotSet是不设置值。
创建ActiveModel方法还有别的,比如通过JSON字符,具体的可以看文档https://www.sea-ql.org/SeaORM/docs/next/basic-crud/insert/#convert-activemodel-back-to-model
然后执行插入方法,具体代码如下

use chrono::{ Local};
use sea_orm::{ActiveModelTrait, ActiveValue, Database, DatabaseConnection, IntoActiveModel};

pub mod entity;
use entity::user::Entity as UserDao;
use entity::user::ActiveModel as UserModel;
use entity::user::Model as Model;
#[tokio::main]
async fn main(){
    let db: DatabaseConnection = Database::connect("mysql://root:root@127.0.0.1:3307/test").await.unwrap();
    let user: UserModel =  UserModel{
        id: ActiveValue::NotSet,
        username: ActiveValue::Set("你好".to_owned()),
        birthday: ActiveValue::Set(Some(Local::now().naive_local())),
        sex: ActiveValue::Set(Some("1".to_owned())),
        address: ActiveValue::Set(Some("address".to_owned())),
    };
/*    let user: Model = Model{
        id: 1,
        username: "admin".to_string(),
        birthday: Some(Local::now().naive_local()),
        sex: Some("1".to_owned()),
        address: Some("address".to_owned()),
    };
    let active_model = user.into_active_model();*/
    let result = user.insert(&db).await.unwrap();
    println!("插入成功!:{:?}",result);
}

多个插入可以调用上述代码UserDao中的insert_many方法,传入ActiveModel数组

主键查找

use entity::user::Entity as UserDao;
 let option = UserDao::find_by_id(1).one(&db).await.unwrap();
    match option {
        None => {}
        Some(user) => println!("查询成功!:{:?}",user)
    }

条件查找

查找用户名是admin的一条用户

use crate::entity::user;
    use entity::user::Entity as UserDao;
    let result = UserDao::find().filter(user::Column::Username.eq("admin")).one(&db).await.unwrap();
    match result {
        None => {}
        Some(user) => println!("查询成功!:{:?}",user)
    }

查找地址是郑州的所有用户

    use crate::entity::user;
    use entity::user::Entity as UserDao;
    let result = UserDao::find().filter(user::Column::Address.eq("郑州")).all(&db).await.unwrap();
    println!("查询成功!:{:?}",result)

查找地址是郑州并且用户名包含admin的所有用户

    use crate::entity::user;
    use entity::user::Entity as UserDao;
    let result = UserDao::find().filter(
        Condition::all().add(user::Column::Address.eq("郑州")).add(user::Column::Username.like("%admin%"))
    ).all(&db).await.unwrap();
    println!("查询成功!:{:?}",result)

分页查找

 
use crate::entity::user;
    use entity::user::Entity as UserDao;
    let mut paginator = UserDao::find().filter(
        Condition::all().add(user::Column::Address.eq("郑州")).add(user::Column::Username.like("%admin%"))
    ).paginate(&db,50);
    //paginate(&db,50)此处第二个参数表示设置单页数量,此方法会返回Paginator对象。
    while let Some(user) = paginator.fetch_and_next().await.unwrap() {
    	//循环从paginate取数据,每次取50条,页数加一,直到没有数据
        println!("查询成功!:{:?}",user)
    }

如果直接获取第几页数据怎么做,下面有方法

    use crate::entity::user;
    use entity::user::Entity as UserDao;
    let mut paginator = UserDao::find().filter(
        Condition::all().add(user::Column::Address.eq("郑州")).add(user::Column::Username.like("%admin%"))
    ).paginate(&db,50);
    //此方法可直接取具体页数,注意是从零开始,需要前端页数加一
    let result = paginator.fetch_page(0).await;
    match result{
        Ok(vec_user) => {println!("{:?}", vec_user)}
        Err(_) => {}
    }

修改数据

修改主键为1的用用户名

    use entity::user::Entity as UserDao;
    let user = UserDao::find_by_id(1).one(&db).await.unwrap().unwrap();
    let mut active_model = user.into_active_model();
    active_model.username = ActiveValue::Set("修改后的用户名".to_owned());
    active_model.update(&db).await.unwrap();

如果想强制更新某个字段可以调用。

active_model.reset(user::Column::Address); //这样更新时字段就会强制带上,可以实现把字段置空

删除数据

很简单

    use entity::user::Entity as UserDao;
    let res = UserDao::delete_by_id(1).exec(&db).await.unwrap();

或者还有一种方法

    use entity::user::Entity as UserDao;
    let res = UserDao::find_by_id(1).one(&db).await.unwrap().unwrap();
    let active_model = res.into_active_model();
    active_model.delete(&db).await.unwrap();

数据库事务操作

可以手动调用db的begin和commit方法,以下是官方例子

let txn = db.begin().await?;

bakery::ActiveModel {
    name: Set("SeaSide Bakery".to_owned()),
    profit_margin: Set(10.4),
    ..Default::default()
}
.save(&txn)
.await?;

bakery::ActiveModel {
    name: Set("Top Bakery".to_owned()),
    profit_margin: Set(15.0),
    ..Default::default()
}
.save(&txn)
.await?;

txn.commit().await?;

总结

以上就是sea-orm入门使用教程,更具体的可以查看sea-orm官方文档https://www.sea-ql.org/SeaORM/docs/index/。后续我可能会再出一篇sea-orm的高级使用教程

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/369846.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

99例电气实物接线及52个自动化机械手动图

给大家分享一些流水线设计中常见的一些结构&#xff0c;这些动态图很直观&#xff0c;有助于大家了解其原理&#xff0c;非常好懂。 1.家庭总电箱接线图 2.经典双控灯接线 3.五孔一开接线 4.电动机点动控制接线&#xff08;不安全&#xff09; 5.电动机自锁接线图&#xff08;…

建筑工程答案在哪搜?九个免费好用的大学生搜题工具 #经验分享#知识分享

大学生必备&#xff0c;这条笔记大数据一定定要推给刚上大学的学弟学妹&#xff01;&#xff01; 1.七燕搜题 这是一个公众号 解题步骤详细解析&#xff0c;帮助你理解问题本质。其他考试领域也能找到答案。 下方附上一些测试的试题及答案 1、据《素问太阴阳明论》所论&…

Java swing——创建对话框JDialog

之前我们讲了怎么建立一个简易的窗口&#xff0c;链接&#xff1a;http://t.csdnimg.cn/l7QSs&#xff0c;接下来继续讲解窗口的进阶。 对话框 上一篇文章中我们讲到了JFrame是一种顶层容器&#xff0c;本文接下来介绍其余的顶层容器。 跟JFrame一样&#xff0c;&#xff0c;这…

「递归算法」:二叉树的所有路径

一、题目 给你一个二叉树的根节点 root &#xff0c;按 任意顺序 &#xff0c;返回所有从根节点到叶子节点的路径。 叶子节点 是指没有子节点的节点。 示例 1&#xff1a; 输入&#xff1a;root [1,2,3,null,5] 输出&#xff1a;["1->2->5","1->3&qu…

微信小程序实现吸顶、网格、瀑布流布局

微信小程序开发通常是在webview模式下编写&#xff0c;但是对小程序的渲染性能有一定的追求&#xff0c;就需要使用Skyline模式进行渲染&#xff0c;同时在这种模式下有也有一些特殊的组件&#xff0c;可以轻松的实现想要的效果&#xff0c;本文将介绍在Skyline模式下如何实现吸…

NoSQL(非关系型数据库)

目录 前言&#xff1a; 一、NoSQL的类别 1.1 键值&#xff08;key-value&#xff09;存储数据库 1.2 列存储数据库 1.3 文档型数据库 1.4 图形数据库 二、NoSQL适应场景 三、在分布式数据库中的CAP原理 3.1 传统的ACID 3.2 CAP 四、什么是BASE 前言&#xff1a; NoS…

【数据结构】二叉树链式结构的实现

简单不先于复杂&#xff0c;而是在复杂之后。 文章目录 1. 二叉树链式结构的实现1.1 前置说明1.2 二叉树的遍历1.2.1 前序、中序以及后序遍历1.2.2 层序遍历 1.3 节点个数以及高度等1.4 二叉树基础oj练习1.5 二叉树的创建和销毁 1. 二叉树链式结构的实现 1.1 前置说明 在学习二…

如何搭建 sqli-labs 靶场保姆级教程(附链接)

一、环境准备 建议采用虚拟机作为靶场环境的承载平台&#xff0c;以实现更灵活、可定制的配置&#xff0c;提高系统资源的利用效率。这种部署方式不仅能够有效隔离实验环境&#xff0c;降低对真实硬件的依赖&#xff0c;还能够快速搭建和复制实验场景&#xff0c;为安全测试和…

IGMP——网际组管理协议

目录 1 IGMP 1.1 IGMP 使用 IP 数据报传递其报文 1.2 IGMP 工作 第一阶段&#xff1a;加入多播组 第二阶段&#xff1a;探询组成员变化情况 1.3 IGMP 采用的一些具体措施&#xff0c;以避免增加大量开销 1 IGMP 标准 1989 年公布的 RFC 1112&#xff08;IGMPv1&#xff…

总观看量已超千万!新就业形态劳动者新春联谊会成功播出

春节到来之际,由中华全国总工会主办,中国海员建设工会、中国国防邮电工会、中国财贸轻纺烟草工会、中华全国总工会文工团联合承办,中国职工发展基金会协办,北京市总工会支持的“温暖有你 共赴美好”2024年新就业形态劳动者新春联谊会,于2月2日晚8点在新华网、央视频、全国总工会…

Java自救手册

目录 访问地址 访问地址&#xff0c;发现不通&#xff0c;无法访问&#xff1a; 网络不通一般有两种情况&#xff1a; Maven 拿Maven 拿到Maven以后 Maven单独的报红 Git git注意&#xff1a; 目录 访问地址 访问地址&#xff0c;发现不通&#xff0c;无法访问&…

Java 使用 ant.jar 执行 SQL 脚本文件

Java 使用 ant.jar 执行 SQL 脚本文件&#xff0c;很简单。 在 pom.xml 中导入 ant 依赖 <dependency><groupId>org.apache.ant</groupId><artifactId>ant</artifactId><version>1.10.11</version> </dependency>sql 脚本文件…

《统计学习方法:李航》笔记 从原理到实现(基于python)-- 第6章 逻辑斯谛回归与最大熵模型(2)6.2 最大熵模型

文章目录 6.2 最大熵模型6.2.1 最大熵原理6.2.3 最大熵模型的学习6.2.4 极大似然估计 《统计学习方法&#xff1a;李航》笔记 从原理到实现&#xff08;基于python&#xff09;-- 第3章 k邻近邻法 《统计学习方法&#xff1a;李航》笔记 从原理到实现&#xff08;基于python&am…

远程桌面时连接不上远程计算机是什么问题

在服务器上搭建网络程序时&#xff0c;我们经常会有需要远程连接上服务器进行相关操作&#xff0c;有些用户在远程桌面的时候&#xff0c;有时会有遇上无法连接到远程计算机的情况。 很多用户都曾遇到在远程桌面时出现“未启用对服务器的远程访问”、“远程计算机已关闭”、“…

vit细粒度图像分类(九)RAMS-Trans学习笔记

1.摘要 在细粒度图像识别(FGIR)中&#xff0c;区域注意力的定位和放大是一个重要因素&#xff0c;基于卷积神经网络(cnn)的方法对此进行了大量探索。近年来发展起来的视觉变压器(ViT)在计算机视觉任务中取得了可喜的成果。与cnn相比&#xff0c;图像序列化是一种全新的方式。然…

【开源】SpringBoot框架开发大学计算机课程管理平台

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 实验课程档案模块2.2 实验资源模块2.3 学生实验模块 三、系统设计3.1 用例设计3.2 数据库设计3.2.1 实验课程档案表3.2.2 实验资源表3.2.3 学生实验表 四、系统展示五、核心代码5.1 一键生成实验5.2 提交实验5.3 批阅实…

Mac安装Homebrew+MySQL+Redis+Nginx+Tomcat等

Mac安装HomebrewMySQLRedisNginxTomcat等 文章目录 Mac安装HomebrewMySQLRedisNginxTomcat等一、Mac安装Mysql 8①&#xff1a;下载②&#xff1a;安装③&#xff1a;配置环境变量④&#xff1a;外部连接测试 二、Mac安装Redis和可视化工具①&#xff1a;安装Redis01&#xff1…

c++用户管理信息(类指针数组)

用户管理信息--类指针数组 类示意图select类示意图MyIterator示意图VetorCstu示意图ClassStu示意图 项目源代码selectselect.hselect.cpp MyIteratorMyIterator.hMyIterator.cpp VetorCstuVetorCstu.hVetorCstu.cpp ClassStuClassStu.hClassStu.cpp main源码 总结---数组管理指…

Linux Shell命令系列--basename获取基本文件名

一、目的 学习linux shell编程的第一步就是熟悉linux的各种命令的使用&#xff0c;本篇开始逐次介绍一些常用linux shell命令。 今天我们来讲解basename命令的使用。 二、介绍 1、基本概念 basename命令首先去除字符串末尾多余的斜杠&#xff08;如果有的话&#xff09;&#…

【AG32VF407】国产MCU+FPGA Verilog双边沿检测输出方波

视频讲解 [AG32VF407]国产MCUFPGA Verilog双边沿检测输出方波 实验过程 本次使用使用AG32VF407开发板中的FPGA&#xff0c;使用双clk的双边沿进行检测&#xff0c;同步输出方波 同时可以根据输出的方波检测clk的频率&#xff0c;以及双clk的相位关系&#xff0c;如下为verilog…