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

news2024/12/29 8:45:00

【从零开始的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的高级使用教程

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【C语言】初阶指针(2)

目录 前言 1. 指针访问数组 1.1 数组名的含义 1.2 使用指针访问数组 2. 一维数组传参的本质 3. 二级指针 4. 指针数组 4.1 指针数组模拟二维数组 结语 前言 在本篇文章中&#xff0c;我们将要一起来探讨指针与数组之间的关系&#xff0c;以及如何理解指针数组及其运用…

Vue.js 中子组件向父组件传值的方法

Vue.js 是一款流行的 JavaScript 前端框架&#xff0c;它提供了一套完整的工具和 API&#xff0c;使得开发者可以更加高效地构建交互式的 Web 应用程序。其中&#xff0c;组件化是 Vue.js 的一个核心概念&#xff0c;通过组件化可以将一个复杂的应用程序拆分成多个独立的部分&a…

通过与chatGPT交流实现零样本事件抽取

1、写作动机&#xff1a; 近来的大规模语言模型&#xff08;例如Chat GPT&#xff09;在零样本设置下取得了很好的表现&#xff0c;这启发作者探索基于提示的方法来解决零样本IE任务。 2、主要贡献&#xff1a; 提出了基于chatgpt的多阶段的信息抽取方法&#xff1a;在第一阶…

VSCode 插件集

文章目录 翻译(英汉词典)Auto Close TagAuto Rename TagBetter CommentsBracket Pair Colorization TogglerChinese (Simplified) (简体中文)colorizeHighlight Matching TagImage previewJAR ViewerLive ServerMarkdown Preview EnhancedMaterial Icon ThemeMaterial Themeope…

uniapp 使用canvas 画海报,有手粘贴即可用(拆成组件了,看后面)

1.直接使用 html部分 <view click"doposter">下载海报</view> <canvas canvas-id"myCanvas" type2d style"width: 370px; height: 550px;opcity:0;position: fixed;z-index:-1;" id"myCanvas" />js 部分 drawBac…

【Vue】2-11、组件的生命周期

一、生命周期 & 声明周期函数 生命周期&#xff08;Life Cycle&#xff09;是值一个组件从 创建 -> 运行 -> 销毁 的整个阶段&#xff0c;强调的是一个时间段。 生命周期函数是由 Vue 框架提供的内置函数&#xff0c;会伴随着组件的生命周期&#xff0c;自动按次序…

【数据分享】1929-2023年全球站点的逐日最高气温数据(Shp\Excel\免费获取)

气象数据是在各项研究中都经常使用的数据&#xff0c;气象指标包括气温、风速、降水、湿度等指标&#xff0c;其中又以气温指标最为常用&#xff01;说到气温数据&#xff0c;最详细的气温数据是具体到气象监测站点的气温数据&#xff01; 之前我们分享过1929-2023年全球气象站…

机器学习数学基础

机器学习基础 1、标量、向量、矩阵、张量2、概率函数、概率分布、概率密度、分布函数3、向量的线性相关性4、最大似然估计5、正态分布(高斯分布)6、向量的外积(叉积)7、向量的内积(点积)8、超平面(H)1、标量、向量、矩阵、张量 标量、向量、矩阵和张量是线性代数中不同…

周期承压下的徐工机械:收入持续负增长,大肆并购风险犹存

撰稿|行星 来源|贝多财经 工程机械行业的发展程度是衡量工业化水平的关键指标&#xff0c;亦是一直以来备受国家与市场关注的高成长板块。 在探索新发展增量的大军中&#xff0c;徐工机械&#xff08;SZ:000425&#xff09;活跃工程机械市场&#xff0c;寻求着利润与品质的最…

springboot140体育馆使用预约平台的设计与实现

简介 【毕设源码推荐 javaweb 项目】基于springbootvue 的 适用于计算机类毕业设计&#xff0c;课程设计参考与学习用途。仅供学习参考&#xff0c; 不得用于商业或者非法用途&#xff0c;否则&#xff0c;一切后果请用户自负。 看运行截图看 第五章 第四章 获取资料方式 **项…

草图导入3d之后渲染模型发光怎么回事?---模大狮模型网

在草图大师中&#xff0c;当导入3D模型之后发现模型发光通常是由于模型的材质属性或灯光设置所导致的。以下是一些可能的原因和解决方法&#xff1a; 材质属性设置&#xff1a;某些3D模型文件可能包含了发光材质属性&#xff0c;导致模型在草图大师中显示为发光状态。您可以尝试…

第四次项目(配置dns服务的正反向解析)

目录 实验要求 实验步骤 一、基础配置 1.1、服务端配置静态IP 1.2、客户端配置静态IP 二、配置dns服务的正向解析 2.1、服务端编辑主配置文件named.conf 2.2、服务端编辑主配置文件named.rfc1912.zones 2.3&#xff0c;服务端编辑数据配置文件&#xff0c;使用拷贝…

opencvb 十七 使用cmake配置opencv c++项目

1、cmake简介 1.1 cmake是什么 CMake是一个开源、跨平台的编译&#xff08;Build&#xff09;工具&#xff0c;是用来构建、测试和打包软件的。它能够用简单的语句来描述所有平台的编译过程。它能够输出各种各样的makefile或者project文件&#xff0c;能测试编译器所支持的C特…

【ASP.NET Core 基础知识】--Web API--创建和配置Web API(一)

一、简介 Web API&#xff08;Web Application Programming Interface&#xff09;的重要性在于其在现代软件开发中扮演着关键的角色。以下是一些关于Web API重要性的方面&#xff1a; 跨平台交互&#xff1a; Web API允许不同平台、不同技术栈的应用程序进行通信。无论是Web…

C#网络爬虫之TianyaCrawler实战经验分享

互联网时代的到来带来了大量的数据&#xff0c;而网络爬虫技术成为了获取这些数据的重要途径之一。如果你是一名C#开发者&#xff0c;那么你可能会对TianyaCrawler这个强大的网络爬虫框架感兴趣。本文将带你深入了解TianyaCrawler&#xff0c;分享它的技术概况、使用场景&#…

为什么光纤目前取代不了网线?

早上好&#xff0c;我的网工朋友。 在布线行业中&#xff0c;光纤与铜缆之间的较量已持续了十多年。 现如今随着云计算、5G等新型业务的不断涌现&#xff0c;数据中心规模不断的扩大&#xff0c;其架构与布线也越来越复杂。 但光纤的轻量化及逐渐降低的成本&#xff0c;使得…

Ubuntu Linux 下安装和卸载cmake 3.28.2版本

一、安装cmake 1.首先&#xff0c;先从cmake官网下载cmake-3.28.2-linux-x86_64.tar.gz 2.用FinalShell 等文件上传工具&#xff0c;将这个压缩包上传到 虚拟机的某个路径去&#xff08;自选&#xff09; 3. cd /usr/local/bin/&#xff0c;然后创建cmake文件夹&#xff0c;…

2024.2.1每日一题

LeetCode 今天看到一个评论挺有意思的&#xff0c;非常符合我现在的状况 简单题 – 稍加思索&#xff0c;嘴角上扬 中等题 – 认真对待&#xff0c;眉头一皱 困难题 – 绞尽脑汁&#xff0c;Ctrl cv 数字游戏 LCP 24. 数字游戏 - 力扣&#xff08;LeetCode&#xff09; 题目…

递归再认识----【详解】内含迷宫和八皇后问题

目录 一.递归&#xff1a; 1.1什么是递归&#xff1f; 1.2 递归示例&#xff1a; ①.打印问题&#xff1a; ②.阶乘问题&#xff1a; 1.3.递归需要遵守的规则&#xff1a; 二.迷宫问题&#xff1a; 说明&#xff1a; 代码详解&#xff1a; 三.八皇后问题&#xff1a; …

秋招面试—JS篇

2024 JavaScript面试题 1.new 操作符的工作原理 ①.创建一个新的空对象 ②.将这个对象的原型设置为函数的 prototype 对象 ③.让函数的this指向该对象&#xff0c;为函数添加属性和方法 ④.最后返回这个对象 2.什么是DOM&#xff0c;什么是BOM? DOM&#xff1a;文档对象…