【从零开始的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_DRIVER和ASYNC_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 schemalet 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代码
// 设置全局日志级别为 infolet 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的高级使用教程
相关文章:
【从零开始的rust web开发之路 三】orm框架sea-orm入门使用教程
【从零开始的rust web开发之路 三】orm框架sea-orm入门使用教程 文章目录 前言一、引入依赖二、创建数据库连接简单链接连接选项开启日志调试 三、生成实体安装sea-orm-cli创建数据库表使用sea-orm-cli命令生成实体文件代码 四、增删改查实现新增数据主键查找条件查找查找用户名…...
SQL中limit的用法
在SQL中,LIMIT是一个用于限制返回结果行数的关键词。它可用于在查询结果中指定返回的行数,从而可以用于分页查询或限制结果集大小。 LIMIT关键词有两种常用的语法格式: LIMIT offset, count:该语法用于指定返回结果的起始位置和…...
vue3 [Vue warn]: Unhandled error during execution of scheduler flush
文章目录 前言一、报错截图二、排除问题思路相关问题 Vue3 优雅解决方法异步组件异同之处:好处:在使用异步组件时,有几个注意点: vue3 定义与使用异步组件 总结 前言 Bug 记录。开发环境运行正常,构建后时不时触发下面…...
【vue2源码】阶段一:Vue 初始化
文章目录 一、项目目录1、主目录2、打包入口 二、构造函数Vue的初始化1、创建 Vue 构造函数2、初始化内容分析2.1 initMixin2.2 stateMixin2.3 eventsMixin2.4 lifecycleMixin2.5 renderMixin 一、项目目录 源码版本:2.7.16 1、主目录 src |-- compiler # 包…...
14.java集合
文章目录 概念Collection 接口概念示例 Iterator 迭代器基本操作:并发修改异常增强循环遍历数组:遍历集合:遍历字符串:限制 list接口ListIteratorArrayList创建 ArrayList:添加元素:获取元素:修…...
二叉树顺序结构堆实现
目录 Test.c测试代码 test1 test2 test3 🎇Test.c总代码 Heap.h头文件&函数声明 头文件 函数声明 🎇Heap.h总代码 Heap.c函数实现 ☁HeapInit初始化 ☁HeapDestroy销毁 ☁HeapPush插入数据 【1】插入数据 【2】向上调整Adjustup❗ …...
正则表达式 与文本三剑客(sed grep awk)
一,正则表达式 (一)正则表达式相关定义 1,正则表达式含义 REGEXP: Regular Expressions,由一类特殊字符及文本字符所编写的模式,其中有些字符(元字符)不表示字符字面意…...
【XR806开发板试用】全志 XR806 OpenHarmony 鸿蒙系统固件烧录
大家好,我是极智视界,本教程详细记录了全志 XR806 OpenHarmony 鸿蒙系统固件烧录的方法。 在上一篇文章《【嵌入式AI】全志 XR806 OpenHarmony 鸿蒙系统固件编译》中咱们已经编译生成了系统镜像,这里把这个编译出来的镜像烧录到 XR806 板子里…...
linux环境安装git、maven、jenkins等
重启 jenkins的命令: systemctl start jenkins 如果没有vim 命令 可以使用 yum install vim 安装 vim git 下载包地址 https://www.kernel.org/pub/software/scm/git/git-2.28.0.tar.gz 1.安装依赖环境: yum install -y curl-devel expat-devel ge…...
RabbitMQ快速上手
首先他的需求实在什么地方。我美哟明显的感受到。 它给我的最大感受就是脱裤子放屁——多此一举,的感觉。 他将信息发送给服务端中间件。在由MQ服务器发送消息。 服务器会监听消息。 但是它不仅仅局限于削峰填谷和稳定发送信息的功能,它还有其他重要…...
SpringBoot activemq收发消息、配置及原理
SpringBoot集成消息处理框架 Spring framework提供了对JMS和AMQP消息框架的无缝集成,为Spring项目使用消息处理框架提供了极大的便利。 与Spring framework相比,Spring Boot更近了一步,通过auto-configuration机制实现了对jms及amqp主流框架…...
视频智能识别安全帽佩戴系统-工地安全帽佩戴识别算法---豌豆云
视频智能识别安全帽佩戴系统能够从繁杂的工地、煤矿、车间等场景下同时对多个目标是否戴安全帽穿反光衣进行实时识别。 当视频智能识别安全帽佩戴系统发现作业人员没有戴安全帽、穿反光衣或者戴安全带,系统会及时报警提醒,并抓拍存档。 视频智能识别安…...
指针的深入理解(三)
这一节主要使用复习回调函数, 利用冒泡模拟实现qsort函数。 qsort 排序使用冒泡排序,主要难点在于运用元素个数和字节数以及基地址控制元素的比较: if里面使用了一个判断函数,qsort可以排序任意的数据,原因就是因为可…...
【Linux C | 网络编程】详细介绍 “三次握手(建立连接)、四次挥手(终止连接)、TCP状态”
😁博客主页😁:🚀https://blog.csdn.net/wkd_007🚀 🤑博客内容🤑:🍭嵌入式开发、Linux、C语言、C、数据结构、音视频🍭 🤣本文内容🤣&a…...
主从数据库MySQL服务重启步骤与注意事项
主从数据库MySQL服务重启步骤与注意事项 实验环境: 172.20.26.34 (主应用服务器) 172.20.26.26 (备应用服务器) 172.20.26.37 (主库服务器) 172.20.26.38 (从库服务器&…...
netlink学习
netlink是什么 netlink是Linux内核中的一种进程间通信(IPC)机制。它允许内核空间与用户空间之间,以及用户空间进程之间进行双向通信。 内核里的很多子系统使用netlink通信,包括网络管理(Routing,Netfilt…...
地理空间分析10——空间数据分析中的地理编码与Python
目录 写在开头1. 地理编码基础1.1 地理编码的基本原理1.1.1 坐标系统1.1.2 地名解析1.1.3 编码算法1.2 Python中使用地理编码的基础知识1.2.1 百度地图API1.2.2 高德地图API1.2.3 腾讯地图API1.3 Python中实现代码2. 逆地理编码2.1 利用Python进行逆地理编码2.1.1 获取高德地图…...
使用“快速开始”将数据传输到新的 iPhone 或 iPad
使用“快速开始”将数据传输到新的 iPhone 或 iPad 使用 iPhone 或 iPad 自动设置你的新 iOS 设备。 使用“快速开始”的过程会同时占用两台设备,因此请务必选择在几分钟内都不需要使用当前设备的时候进行设置。 确保你当前的设备已连接到无线局域网,并…...
计算机网络(第六版)复习提纲13
前同步码,七位1010交替出现,帧开始码:10101011 为什么没有帧结束?曼彻斯特码传播完成后,维持高电平,不再跳变,因此不必要设置帧结束。 3.无效的MAC帧 i.数据字段的长度与长度字段的值不一致&…...
[office] excel2010双向条形图制作 #经验分享#微信
excel2010双向条形图制作 本教程为大家介绍一下excel2010中excel2010双向条形图制作方法。 1.选中工作区域 2.点击插入-->图表,选择条形图 3.为美观可将中间竖线可去掉 4.方法是选中竖线,右击-->删除 5.接下来将图例靠上,选中图例,右击-->设置图例格式-->图例选项…...
synchronized 学习
学习源: https://www.bilibili.com/video/BV1aJ411V763?spm_id_from333.788.videopod.episodes&vd_source32e1c41a9370911ab06d12fbc36c4ebc 1.应用场景 不超卖,也要考虑性能问题(场景) 2.常见面试问题: sync出…...
Leetcode 3577. Count the Number of Computer Unlocking Permutations
Leetcode 3577. Count the Number of Computer Unlocking Permutations 1. 解题思路2. 代码实现 题目链接:3577. Count the Number of Computer Unlocking Permutations 1. 解题思路 这一题其实就是一个脑筋急转弯,要想要能够将所有的电脑解锁&#x…...
什么是库存周转?如何用进销存系统提高库存周转率?
你可能听说过这样一句话: “利润不是赚出来的,是管出来的。” 尤其是在制造业、批发零售、电商这类“货堆成山”的行业,很多企业看着销售不错,账上却没钱、利润也不见了,一翻库存才发现: 一堆卖不动的旧货…...
【论文笔记】若干矿井粉尘检测算法概述
总的来说,传统机器学习、传统机器学习与深度学习的结合、LSTM等算法所需要的数据集来源于矿井传感器测量的粉尘浓度,通过建立回归模型来预测未来矿井的粉尘浓度。传统机器学习算法性能易受数据中极端值的影响。YOLO等计算机视觉算法所需要的数据集来源于…...
Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)
引言:为什么 Eureka 依然是存量系统的核心? 尽管 Nacos 等新注册中心崛起,但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制,是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...
JDK 17 新特性
#JDK 17 新特性 /**************** 文本块 *****************/ python/scala中早就支持,不稀奇 String json “”" { “name”: “Java”, “version”: 17 } “”"; /**************** Switch 语句 -> 表达式 *****************/ 挺好的ÿ…...
Swagger和OpenApi的前世今生
Swagger与OpenAPI的关系演进是API标准化进程中的重要篇章,二者共同塑造了现代RESTful API的开发范式。 本期就扒一扒其技术演进的关键节点与核心逻辑: 🔄 一、起源与初创期:Swagger的诞生(2010-2014) 核心…...
Device Mapper 机制
Device Mapper 机制详解 Device Mapper(简称 DM)是 Linux 内核中的一套通用块设备映射框架,为 LVM、加密磁盘、RAID 等提供底层支持。本文将详细介绍 Device Mapper 的原理、实现、内核配置、常用工具、操作测试流程,并配以详细的…...
AI病理诊断七剑下天山,医疗未来触手可及
一、病理诊断困局:刀尖上的医学艺术 1.1 金标准背后的隐痛 病理诊断被誉为"诊断的诊断",医生需通过显微镜观察组织切片,在细胞迷宫中捕捉癌变信号。某省病理质控报告显示,基层医院误诊率达12%-15%,专家会诊…...
Linux离线(zip方式)安装docker
目录 基础信息操作系统信息docker信息 安装实例安装步骤示例 遇到的问题问题1:修改默认工作路径启动失败问题2 找不到对应组 基础信息 操作系统信息 OS版本:CentOS 7 64位 内核版本:3.10.0 相关命令: uname -rcat /etc/os-rele…...
