SQLx:一款优秀的异步 SQL 工具库

news2026/5/8 7:29:35
SQLx一款优秀的异步 SQL 工具库传统 ORM 工具会引入冗余抽象而原生 SQL 操作又容易出现运行时错误。SQLx 作为 Rust 生态中备受推崇的 SQL 工具库以编译时 SQL 验证为核心卖点兼顾异步支持、轻量等特性解决了上述痛点。本文将从 SQLx 将逐步讲解其特性、快速上手流程、实战案例及进阶用法带读者快速掌握这一强大工具。SQLx 介绍SQLx 是一个纯 Rust 编写的异步 SQL 工具库并非传统意义上的 ORM更偏向是类型安全的 SQL 执行器。它的核心设计理念是将 SQL 的验证从运行时提前到编译时通过宏在编译期与数据库建立临时连接校验SQL语法、字段名、数据类型的合法性从源头避免大量低级错误。与其他 Rust 数据库工具如 Diesel、SeaORM 等相比SQLx 具有以下鲜明特点无 DSL领域特定语言直接使用原生 SQL无需学习额外的查询语法降低学习成本同时保留 SQL 的灵活性。异步优先基于 tokio 等异步运行时设计适配 Rust 异步生态性能优于同步数据库工具。多数据库支持支持 PostgreSQL、MySQL、SQLite 等主流数据库切换数据库时无需大幅修改代码。轻量无依赖核心功能简洁不引入过多冗余依赖编译速度快适合各类 Rust 项目。简单来说SQLx 的目标是让开发者既能享受原生 SQL 的灵活又能获得 Rust 的类型安全和编译时检查同时兼顾异步场景的性能需求。特性讲解编译时SQL验证传统 SQL 操作中SQL 语法错误、字段名拼写错误、字段类型不匹配等问题只有在程序运行时执行 SQL 才能发现增加了调试成本和线上风险。而 SQLx 通过query!、query_as!等宏在编译期就会连接数据库对 SQL 语句进行全方位校验。实现原理编译时SQLx 的宏会读取环境变量中的数据库连接地址如 DATABASE_URL建立临时只读连接将 SQL 语句发送给数据库进行解析和校验校验通过后才会继续编译若 SQL 存在错误比如字段名错误、语法错误则直接编译失败给出明确的错误提示。示例编译时报错若数据库中users表不存在agee字段以下代码会在编译时直接报错无需运行程序// 编译时会报错column agee does not existletuser:Usersqlx::query_as!(User,SELECT id, name, agee FROM users WHERE id $1,1).fetch_one(pool).await?;异步支持与连接池SQLx 基于异步 I/O 设计完全兼容 tokio、async-std 等 Rust 主流异步运行时无需额外适配即可在异步项目中使用。同时SQLx 内置了高效的连接池实现自动管理数据库连接的创建、复用和释放避免频繁建立连接带来的性能开销。连接池带来的好处有限制最大连接数防止数据库因连接过多而崩溃。复用空闲连接减少 TCP 握手和认证的开销提升查询性能。自动处理连接超时和重连提升系统稳定性。SQLx 提供了PgPoolPostgreSQL、MySqlPoolMySQL等连接池类型配置简单可根据项目需求调整连接池大小、超时时间等参数。结构体自动映射SQLx 支持将查询结果自动映射到 Rust 结构体无需手动解析查询结果如逐字段读取、类型转换大幅简化代码。只需为结构体实现FromRow特征可通过派生宏自动实现即可通过query_as!宏直接将查询结果映射为结构体实例。usesqlx::FromRow;// 派生 FromRow 特征#[derive(Debug, FromRow)]structUser{id:i32,name:String,email:OptionString,// 可选字段对应数据库中的 NULLcreated_at:chrono::NaiveDateTime,// 支持时间类型自动转换}// 查询单条记录并映射为 User 结构体letuser:Usersqlx::query_as!(User,SELECT id, name, email, created_at FROM users WHERE id $1,1).fetch_one(pool).await?;println!({:?},user);事务支持SQLx 提供了完善的事务支持同时支持嵌套事务通过保存点机制实现确保数据一致性。此外SQLx 还提供了事务闭包模式自动处理事务的提交和回滚减少手动操作的冗余代码降低出错风险。迁移工具Migrations数据库迁移是项目迭代过程中不可或缺的环节SQLx 内置了迁移工具 sqlx-cli支持创建、应用、回滚迁移脚本统一管理数据库表结构的变更。迁移脚本采用 SQL 文件编写支持版本控制。快速上手下面以 PostgreSQL 为例讲解 SQLx 的环境搭建、连接数据库、以及基础 CRUD 操作。环境准备安装依赖在Cargo.toml中添加 SQLx 依赖并指定数据库类型和异步运行时 tokio安装 sqlx-cli 迁移工具通过 Cargo 安装 sqlx-cli用于管理数据库迁移cargoinstallsqlx-cli配置数据库连接创建.env文件配置数据库连接地址这里改为你实际的数据库连接配置DATABASE_URLpostgres://username:passwordlocalhost:5432/sqlx_demo基础 CRUD 操作创建迁移脚本创建 users 表使用 sqlx-cli 创建迁移脚本用于创建users表sqlx migrateadd-rcreate_users执行后会在项目根目录生成migrations文件夹并同步创建迁移与回滚这两个脚本文件XXXXXX_create_users.up.sqlXXXXXX_create_users.down.sql编辑迁移脚本文件CREATETABLEIFNOTEXISTSusers(idSERIALPRIMARYKEY,nameVARCHAR(50)NOTNULL,emailVARCHAR(100)UNIQUE,created_atTIMESTAMPNOTNULLDEFAULTNOW());编辑回滚脚本文件DROPTABLEIFEXISTSusers;执行迁移命令sqlx migrate run编写代码编辑src/main.rs实现用户的新增、查询、更新、删除usechrono::NaiveDateTime;usedotenvy::dotenv;usesqlx::{PgPool,prelude::FromRow};// 定义 User 结构体与 users 表对应#[derive(Debug, FromRow)]structUser{id:i32,name:String,email:OptionString,created_at:NaiveDateTime,}// 初始化数据库连接池asyncfninit_pool()-PgPool{dotenv().ok();letdatabase_urlstd::env::var(DATABASE_URL).expect(DATABASE_URL environment variable not set);PgPool::connect(database_url).await.expect(Failed to connect to database)}// 新增用户asyncfncreate_user(pool:PgPool,name:str,email:Optionstr)-ResultUser,sqlx::Error{letusersqlx::query_as!(User,INSERT INTO users (name, email) VALUES ($1, $2) RETURNING *,name,email).fetch_one(pool).await?;Ok(user)}// 根据ID查询用户asyncfnget_user_by_id(pool:PgPool,id:i32)-ResultOptionUser,sqlx::Error{letusersqlx::query_as!(User,SELECT * FROM users WHERE id $1,id).fetch_optional(pool).await?;Ok(user)}// 更新用户名称asyncfnupdate_user_name(pool:PgPool,id:i32,new_name:str)-Resultu64,sqlx::Error{letresultsqlx::query!(UPDATE users SET name $1 WHERE id $2,new_name,id).execute(pool).await?;Ok(result.rows_affected())// 返回受影响的行数}// 删除用户asyncfndelete_user(pool:PgPool,id:i32)-Resultu64,sqlx::Error{letresultsqlx::query!(DELETE FROM users WHERE id $1,id).execute(pool).await?;Ok(result.rows_affected())}#[tokio::main]asyncfnmain()-Result(),sqlx::Error{// 初始化连接池letpoolinit_pool().await;println!(Connected to database successfully!);// 新增用户letnew_usercreate_user(pool,Alice,Some(aliceexample.com)).await?;println!(Created user: {:?},new_user);// 根据ID查询用户letuserget_user_by_id(pool,new_user.id).await?;println!(Found user: {:?},user);// 更新用户名称letaffected_rowsupdate_user_name(pool,new_user.id,Alice Smith).await?;println!(Updated {} rows,affected_rows);// 删除用户letaffected_rowsdelete_user(pool,new_user.id).await?;println!(Deleted {} rows,affected_rows);Ok(())}SQLx 进阶连接池优化配置默认的连接池配置可能无法满足高并发场景的需求可通过PgPoolOptionsPostgreSQL自定义连接池参数优化性能usedotenvy::dotenv;usesqlx::postgres::PgPoolOptions;asyncfninit_optimized_pool()-PgPool{letdatabase_urlstd::env::var(DATABASE_URL).expect(DATABASE_URL not set);PgPoolOptions::new().max_connections(20)// 最大连接数根据数据库性能调整.min_connections(5)// 最小空闲连接数减少连接建立开销.acquire_timeout(std::time::Duration::from_secs(3))// 连接获取超时时间.idle_timeout(std::time::Duration::from_secs(60))// 空闲连接超时时间.connect(database_url).await.expect(Failed to create optimized pool)}批量操作优化在需要批量插入、更新数据时应当避免循环调用单条操作这会导致频繁与数据库交互严重影响性能可以使用 SQLx 的批量操作功能减少数据库交互次数。// 新建用户专用结构体#[derive(Debug)]pubstructNewUser{pubname:String,pubemail:OptionString,}asyncfnbatch_insert_users(pool:PgPool,new_users:VecNewUser,)-ResultVecUser,sqlx::Error{ifnew_users.is_empty(){returnOk(Vec::new());}// 开启事务letmuttxpool.begin().await?;// 动态生成批量插入的占位符($1,$2), ($3,$4), ...letplaceholders:VecStringnew_users.iter().enumerate().map(|(i,_)|format!((${}, {}),i*21,i*22)).collect();// 构建完整 SQLletsqlformat!(INSERT INTO users (name, email) VALUES {} RETURNING id, name, email, created_at,placeholders.join(, ));// 绑定所有参数letmutquerysqlx::query_as::_,User(sql);foruserinnew_users{queryquery.bind(user.name).bind(user.email);}// 执行letusers:VecUserquery.fetch_all(mut*tx).await?;// 提交事务tx.commit().await?;Ok(users)}事务进阶嵌套事务与保存点SQLx 支持嵌套事务通过保存点Savepoint机制实现当嵌套事务失败时仅回滚当前嵌套层级的操作不影响外层事务。asyncfnnested_transaction_example(pool:PgPool)-Result(),sqlx::Error{letmuttxpool.begin().await?;// 外层事务操作插入用户letusersqlx::query_as!(User,INSERT INTO users (name, email) VALUES ($1, $2) RETURNING *,Bob,Some(bobexample.com)).fetch_one(mut*tx).await?;// 创建保存点等价于嵌套事务sqlx::query(SAVEPOINT nested_tx).execute(mut*tx).await?;// 嵌套事务内操作更新用户名sqlx::query!(UPDATE users SET name $1 WHERE id $2,Bob Brown,user.id// 修复弃用 last_insert_id()直接用结构体id).execute(mut*tx).await?;// 回滚到保存点仅撤销嵌套内的操作不影响外层sqlx::query(ROLLBACK TO SAVEPOINT nested_tx).execute(mut*tx).await?;// 释放保存点可选sqlx::query(RELEASE SAVEPOINT nested_tx).execute(mut*tx).await?;// 提交外层事务插入操作生效tx.commit().await?;Ok(())}编译时验证的离线模式默认情况下SQLx 的编译时验证需要连接真实数据库但在 CI/CD 环境或生产环境编译时可能无法访问数据库。此时可使用 SQLx 的离线模式提前生成验证元数据避免编译时依赖数据库。生成离线元数据cargosqlx prepare执行后会生成.sqlx目录目录下包含着所有 SQL 验证的元数据。编译时SQLx 会读取该文件进行验证无需连接数据库。总结随着 Rust 异步生态的不断完善SQLx 也在持续迭代未来将支持更多数据库特性、优化性能、简化使用流程。不过需要注意的是SQLx 的版本还处于 0.x 阶段并没有完全稳定下来有时候会存在一些破坏性更新这点在使用时仍需要注意。

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

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

相关文章

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…

网络编程(Modbus进阶)

思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…

UE5 学习系列(二)用户操作界面及介绍

这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…

利用最小二乘法找圆心和半径

#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造&#xff0c;完美适配AGV和无人叉车。同时&#xff0c;集成以太网与语音合成技术&#xff0c;为各类高级系统&#xff08;如MES、调度系统、库位管理、立库等&#xff09;提供高效便捷的语音交互体验。 L…

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…

接口测试中缓存处理策略

在接口测试中&#xff0c;缓存处理策略是一个关键环节&#xff0c;直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性&#xff0c;避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明&#xff1a; 一、缓存处理的核…

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?

编辑&#xff1a;陈萍萍的公主一点人工一点智能 未来机器人的大脑&#xff1a;如何用神经网络模拟器实现更智能的决策&#xff1f;RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战&#xff0c;在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…

Linux应用开发之网络套接字编程(实例篇)

服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…