You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将Rust的Vec<ProductData>转换为PostgreSQL自定义类型数组并插入

解决Rust中PostgreSQL自定义类型数组的序列化问题

解决步骤

1. 配置依赖

在Cargo.toml中添加postgres crate并启用所需特性,覆盖自定义类型推导、uuid和numeric类型的支持:

[dependencies]
postgres = { version = "0.19", features = ["derive", "uuid", "numeric"] }
uuid = { version = "1.0", features = ["v4", "postgres"] }
bigdecimal = "0.3" # 对应PostgreSQL的numeric类型

2. 定义匹配的Rust结构体

创建与PostgreSQLproduct_data类型字段完全对应的结构体,通过derive宏自动实现序列化/反序列化逻辑,同时指定PostgreSQL类型名:

use postgres::{types::{ToSql, FromSql}, Client, Error};
use uuid::Uuid;
use bigdecimal::BigDecimal;

#[derive(Debug, ToSql, FromSql)]
#[postgres(type_name = "product_data")]
struct ProductData {
    id: Uuid,
    reference: String,
    name: String,
    description: Option<String>, // 字段允许NULL时用Option包裹
    price: BigDecimal,
}

注意:结构体字段名必须和PostgreSQL自定义类型的字段名完全一致(PostgreSQL默认小写);若字段允许空值,必须使用Option<T>类型。

3. 调用存储过程

直接将Vec<ProductData>作为参数传入execute方法,postgres crate会自动处理数组的序列化:

fn update_products(client: &mut Client, location_id: Uuid, products: Vec<ProductData>) -> Result<(), Error> {
    client.execute(
        "CALL update_products($1, $2)",
        &[&location_id, &products]
    )?;
    Ok(())
}

手动实现ToSql出错的原因

PostgreSQL的自定义类型数组有严格的二进制序列化规则:

  • 先传递数组元数据(维度、元素数量、是否为空等)
  • 再依次传递每个元素的序列化数据,单个元素的格式需与自定义类型的二进制格式完全匹配

手动实现时极易忽略元数据的正确构造(比如长度计算错误、维度标记缺失),导致数据库端解析时触发insufficient data left in message错误。使用derive宏可以自动处理这些底层细节,避免手动实现的疏漏。

额外注意事项

  • 确保PostgreSQL用户有权限调用update_products存储过程,以及访问product_data自定义类型
  • 若使用tokio-postgres异步客户端,代码逻辑完全一致,仅需替换对应的客户端类型

内容的提问来源于stack exchange,提问作者Fong-Wan Chau

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 08:13:41