网站首页 > 知识剖析 正文
sqlx 是一个用于 Rust 编程语言的数据库操作库,支持异步操作并且提供了类型安全的查询。
sqlx最大的特点就是可以灵活地组SQL语句,大部分数据库操作都只需要掌握sqlx::query这个函数,就能使用。
使用sqlx操作数据库有两种方式:sqlx::query函数调用和sqlx::query!宏。如:
基本使用
依赖配置:
# 数据库框架
sqlx = { version="0.7",features = ["mysql", "runtime-tokio-rustls", "chrono"] }
# 异步框架
tokio = { version = "1.45", features = ["full"] }
# 环境变量操作库
dotenv = "0.15"
sqlx是异步操作库,需要一个异步运行时,这里使用tokio。为了使用sqlx的query!宏,需要配置“DATABASE_URL”环境变量,这里使用 dotenv来读取环境变量。
我们在开发中,最常用的SQL操作就是增、删、查、改。除此之外,还可能在软件开始时对数据库进行初始化(建库、建表、建索引等)。
连接数据库:
dotenv::dotenv().ok();
let database_url = std::env::var("DATABASE_URL").expect("必须设置环境变量:DATABASE_URL");
let pool: Pool<MySql> = MySqlPoolOptions::new()
.max_connections(5)
.connect(&database_url)
.await?;
如果要使用query!宏,必须配置 'DATABASE_URL'环境变量,如:
set DATABASE_URL="mysql://root:root@localhost/db_chess"
还有一个需要注意的就是sqlx是的操作是异步的,所以需要在async函数中进行。
执行SQL文件:
执行SQL文件不常用。但为了提升软件的安装体验,常常在软件初始化时(安装后第一次启动)把数据库也初始化了。执行SQL文件非常简单:
sqlx::query_file!("db/database.sql").execute(&pool).await?;
针对比较小的文件,可以以上的方式,但如果SQL文件非常大(包含迁移数据),那以上的方法就行不通。
通常情况下,执行超大的SQL文件(1G以上)需要进行“流式处理”。简单地说,就是读取SQL文件,通过分号(;)判断SQL语言,一条一条地执行。
当然,更好的方式是使用 sqlx migrate 工具进行来执行超大的SQL文件。sqlx提升了命令行工具和代码集成两种方式,以下是代码集成方式示例:
let migrator = sqlx::migrate::Migrator::new(Path::new("./migrations")).await.unwrap();
migrator.run(&pool).await.unwrap(); // 执行SQL。
代码中的"./migrations"是保存有SQL文件的目录。
CURD操作:
使用Rust进行SQL操作时,可以使用query函数和query!宏,两种方式比较相似:
// query!宏方式
sqlx::query!("insert into tb_user(username, password) values(?, ?)","小明","123")
.execute(&pool).await?;
// query函数方式
sqlx::query( "insert into tb_user(username, password) values(?, ?)")
.bind("小明").bind("123").execute(&pool).await?;
两种方式的区别是:query!宏可以在编译时检查SQL语句,而query函数则不会检测。当然,如果使用了RustRover,正确配置数据源后,在编辑器中是可以看出错误的。
对于有返回信息query,还可以直接将数据映射成结构体对象(如:User对象)或返回单个数据(查询指定用户ID对应的用户名等):
// 插入数据时,获取新插入行的行的ID
// 使用宏查询,需要设置环境变量:DATABASE_URL
let res = sqlx::query!("insert into tb_user(username, password) values(?, ?)","小明","123")
.execute(&pool).await?;
let id = res.last_insert_id(); // 获取插入数据列的ID
// 用户结构定义,如果需要从数据库反序列化,需要 加上sqlx::FromRow
#[derive(Debug, sqlx::FromRow)]
struct User {
id: i64,
username: String,
password: String,
}
// 查询指定用户信息,返回查到的第一条数据
let user = sqlx::query_as::<_, User>("select * from tb_user where id = ?")
.bind(3) .fetch_optional(&pool).await;
match user {
Ok(user) => {println!("{:?}", user)}
Err(err) => {println!("{}", err);}
}
// 还有一个fetch_one函数,但如果没有查到数据,
// 将会返回错误: "no rows returned by a query that expected to return at least one row"
// 可以使用fetch_all函数查询多条数据,返回Vec数组;
// 如果没有查询到数据,返回空的Vec数组
let users = sqlx::query_as::<_, User>("select * from tb_user")
.fetch_all(&pool).await?;
println!("用户:{:?}", users);
事务操作:
有的时候,我们需要保证一组数据操作“完整”地执行成功,比如:注册用户时要保证插入用户数据成功、设置用户基础角色成功。
事务的作用就是保证一组SQL(多条SQL)操作能够全部执行成功;要么有任何一条SQL执行失败时,撤销之前执行成功的SQL操作,保证并不会对数据库造成影响。
上述第64行故意写了一个错误的SQL,执行该SQL时会失败。在这之前,前面的插入用户数据其实已经成功。
如果没有事务,这就会造成插入数据成功而关联用户角色失败的情况。总体来说,这个操作是失败的,因为结果返回了Error,但数据库中却多了一条数据。这显然不是我们想要的。
但是,加上事务之后,如果在我们调用提交(commit)前发生错误,前面操作成功的语句都会回滚(撤销)。
结语:简单、直接、够用
用sqlx操作数据库就是这么回事:
- 写SQL不绕弯 - 直接写原生SQL,query/query!两个核心方法搞定90%需求
- 类型安全不操心 - query!宏在编译时帮你检查SQL错误
- 异步操作不卡顿 - 配合tokio运行时,高并发场景稳如老狗
- 事务保平安 - 关键操作加上事务,失败自动回滚不埋坑
实际项目中记住三点:
- 小文件用query_file!
- 大迁移用Migrator
- 关键操作包事务
最后提醒:配置好DATABASE_URL环境变量,你的SQL才能在编译期被检查。别嫌麻烦,这步能省你一半调试时间。
猜你喜欢
- 2025-07-08 SQL中的EXISTS函数你有用过吗?(oracle数据库exists函数用法)
- 2025-07-08 美团面试特有:写个 SQL 语句然后问加了哪些锁
- 2025-07-08 数据库系统原理:数据插入(数据库插数据语句)
- 2025-07-08 10W 行级别数据的 Excel 导入优化记录
- 2025-07-08 excel批量生成sql脚本(excel批量生成数据)
- 2025-07-08 数据库教程-SQL Server查询结果列转行实现与分析
- 2025-07-08 SQL 中的 (+)用法(sql ||是什么)
- 2025-07-08 5分钟掌握现有sql逻辑添加逻辑 deepseek提示词。亲身实战
- 2025-07-08 SQL入门基础-如何串联拼接多列的值?
- 2025-07-08 SQL 如何进行并集、交集、差集等集合运算
- 最近发表
- 标签列表
-
- xml (46)
- css animation (57)
- array_slice (60)
- htmlspecialchars (54)
- position: absolute (54)
- datediff函数 (47)
- array_pop (49)
- jsmap (52)
- toggleclass (43)
- console.time (63)
- .sql (41)
- ahref (40)
- js json.parse (59)
- html复选框 (60)
- css 透明 (44)
- css 颜色 (47)
- php replace (41)
- css nth-child (48)
- min-height (40)
- xml schema (44)
- css 最后一个元素 (46)
- location.origin (44)
- table border (49)
- html tr (40)
- video controls (49)