Rust in Everything
基于 sqlx 0.9.0

核心抽象

这一部分是本卷的重点:和具体数据库无关的 trait 都在 sqlx-core/src/ 里,驱动 crate(这一卷只看 sqlx-postgres)负责实现它们,sqlx crate 原样重新导出。相关的文件不大:database.rs、connection.rs、executor.rs、acquire.rs 加起来约 800 行,query*.rs、sql_str.rs、raw_sql.rs、query_builder.rs 约 2.6k 行(其中 1.1k 多行是文档注释),类型、行和错误各几百行。

前三章沿着查询主线走一遍「执行之前」:一个数据库由哪些类型组成,查询交给谁执行,查询本身是什么。后三章是执行之后:值怎么编码解码,行怎么变成 Rust 类型,出错时是什么。

  1. Database 与关联类型:Database 没有方法,只是一张关联类型表,各组件 trait 用 Database = Self 指回来;0.9 起只剩 ValueRef<'r> 带生命周期;跨数据库的泛型函数要逐条写约束,运行时选库用 Any 驱动,它能处理的值只有十种。
  2. Executor 与 Acquire:Executor 十个方法里必须实现的是 fetch_many、fetch_optional、prepare_with(开了 macros 还有 describe);Execute::take_arguments 返回 None 走简单查询;&Pool 每次调用重新取连接,Transaction 要写 &mut *tx;要在一个函数里跑多条查询,收 Acquire。
  3. Query、QueryAs 与 SqlSafeStr:三种查询类型一层包一层;bind 当场编码、错误留到执行时抛出;0.9 的 SqlSafeStr 让 query(&format!(..)) 编译不过,SqlStr 让查询可以是 'static;raw_sql 和 QueryBuilder。
  4. 类型:Type、Encode、Decode:Rust 类型和 SQL 类型怎么对应、怎么编码成参数、怎么从列里解码,Option<T> 和 NULL,#[derive(sqlx::Type)]。
  5. Row 与 FromRow:按列名或下标取值,类型检查发生在哪里,元组和 #[derive(FromRow)] 怎么把一行变成结构体。
  6. 错误:Error 的各个分支,Postgres 的错误码和约束名,怎么判断唯一约束冲突。
flowchart TB
  db["Database 类型表"] --> exec["Executor 拿什么跑"]
  db --> query["Query 跑什么"]
  query -->|Execute| exec
  query --> enc["Encode 参数"]
  exec --> row[Row]
  row --> dec["Decode / FromRow"]
  exec --> err[Error]

Postgres 驱动怎么实现这些 trait(协议消息、语句缓存、类型 OID)在 03 Postgres 驱动;&Pool 背后的 acquire 在 04 连接池。

💬 关联讨论

发起讨论
加载中...