sqlx概览
开始之前,我们需要一些准备工作,包括:创建用于演示的数据库及数据、创建一个 Rust 项目以及为项目编写一些基础性代码。sqlx的查询构造器
本章将讨论 sqlx 的查询构造器。sqlx 提供了多种查询构造器:`query`、`query_as`、`query!`、`query_as!`、`QueryBuilder`等,合理使用将提升效率。这些查询构造器用来生成数据库所需要的 SQL 语句,不要被它们的名字迷惑了——认为它们是用来查询数据(SQL中的`SELECT`行为)sqlx查询数据
本章将讨论使用 sqlx 执行 `SELECT` 语句,对数据进行查询。sqlx实现增删改
本章将讨论使用 sqlx 进行增删改(`INSERT/DELETE/UPDATE`)操作。使用sqlx的事务实现转账
本章我们将通过用户之间转账来讨论 sqlx 的事务。为了保证转账的完整性、正确性,我们必须使用事务来处理。使用sqlx的QueryBuilder构建复杂、动态的查询
本章我们讨论如何优雅方便地使用 sqlx 构建复杂的、动态的 SQL。sqlx 提供了 [`QueryBuilder`](https://docs.rs/sqlx/latest/sqlx/struct.QueryBuilder.html) 结构体,它可以方便地实现 SQL 的构建。sqlx优雅地实现IN查询
在日常开发中,`IN` 查询是非常常见的需求,你会怎么来处理呢?借助 sqlx 的`QueryBuilder` 可以方便地实现。
使用sqlx的QueryBuilder构建复杂、动态的查询
本章我们讨论如何优雅方便地使用 sqlx 构建复杂的、动态的 SQL。sqlx 提供了 QueryBuilder
结构体,它可以方便地实现 SQL 的构建。
QueryBuilder
常用方法
push()
:追加 SQL 语句push_bind()
:追加绑定参数build()
:构建最终的查询。结果和query()
类似。build_query_as()
:构建最终的查询,结果和query_as()
类似。
// query_as
sqlx::query_as("SELECT * FROM member WHERE id=? AND is_del=?").bind(id).bind(false);
// QueryBuild
let mut q = QueryBuilder::new("SELECT * FROM member WHERE id="); // 不用占位符!
q.push_bind(id)
.push(" AND is_del=") // 不用占位符!
.push_bind(false);
使用 QueryBuilder
改造 list()
改造前:
pub async fn list(
conn: &sqlx::MySqlPool,
page: u32,
) -> Result<Paginate<Vec<model::member::Member>>> {
let count: (i64,) = sqlx::query_as("SELECT COUNT(*) FROM member")
.fetch_one(conn)
.await
.map_err(Error::from)?;
let sql = format!(
"SELECT * FROM member ORDER BY id DESC LIMIT {} OFFSET {}",
DEFAULT_PAGE_SIZE,
page * DEFAULT_PAGE_SIZE
);
let data = sqlx::query_as(&sql)
.fetch_all(conn)
.await
.map_err(Error::from)?;
Ok(Paginate::new(count.0 as u32, page, data))
}
改造后:
我们使用 QueryBuilder
代替了之前使用 format!
拼接 SQL 的做法。
改造前:
pub async fn exists(conn: &sqlx::MySqlPool, name: &str, id: Option<u32>) -> Result<bool> {
let sql = "SELECT COUNT(*) FROM member WHERE name=?";
let with_id_sql: String;
let q = match id {
Some(id) => {
with_id_sql = format!("{} AND id<>?", sql);
sqlx::query_as(&with_id_sql).bind(&name).bind(id)
}
None => sqlx::query_as(sql).bind(&name),
};
let count: (i64,) = q.fetch_one(conn).await.map_err(Error::from)?;
Ok(count.0 > 0)
}
改造后:
pub async fn exists(conn: &sqlx::MySqlPool, name: &str, id: Option<u32>) -> Result<bool> {
let mut q = sqlx::QueryBuilder::new("SELECT COUNT(*) FROM member WHERE name=");
q.push_bind(name);
if let Some(id) = id {
q.push(" AND id<>").push_bind(id);
};
let count: (i64,) = q
.build_query_as()
.fetch_one(conn)
.await
.map_err(Error::from)?;
Ok(count.0 > 0)
}
再次提醒:**和
query()/query_as()
不同,QueryBuilder
的push()
方法的 SQL 语句里,不需要使用?
占位符
再次提醒:**和 query()/query_as()
不同,QueryBuilder
的push()
方法的 SQL 语句里,不需要使用 ?
占位符