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

Rust使用tokio-postgres插入JSONB报类型不匹配错误求助

问题

尝试向PostgreSQL的users表插入JSON数据时触发运行时错误,编译无异常,错误信息如下:

Error: Error { kind: ToSql(0), cause: Some(WrongType { postgres: Json, rust: "alloc::string::String" }) }

表中user_report字段为JSONB类型,相关代码及依赖配置如下:

插入数据函数

async fn insert_values(client: &Client, user: Report) -> Result<(), Error> {
    // Serialize the user data to JSON
    let user_json = json!({
        "username": user.username,
        "gender": {
            "val": user.gender.val,
        },
    });
     let res = serde_json::to_string(&user_json ).unwrap();
    // Execute the SQL statement to insert values
    client
        .execute("INSERT INTO users (user_report) VALUES ($1)", &[&res])
        .await?;
    Ok(())
}

建表函数

async fn create_table(client: &Client) -> Result<(), Error> {
    // Define the SQL statement to create a table if it doesn't exist
    let command = r#"
        CREATE TABLE IF NOT EXISTS users (
            id SERIAL PRIMARY KEY,
            user_report JSONB
        )"#;

    // Execute the SQL statement to create the table
    client.execute(command, &[]).await?;
    Ok(())
}

Cargo.toml依赖配置

[dependencies]
serde = {version = "1.0.164", features=["derive"]}
serde_json = "1.0.103"
tokio-postgres = [version = "0.7.10", features= ["with-serde_json-1"]]
tokio = { version = "1", features = ["full"] }

解决方案

错误根源是你将JSON序列化为String类型传入,但tokio-postgres启用的with-serde_json-1特性支持直接传入serde_json::Value类型,无需转成字符串。具体修改如下:

修改后的插入函数

async fn insert_values(client: &Client, user: Report) -> Result<(), Error> {
    // Serialize the user data to JSON(得到serde_json::Value类型)
    let user_json = json!({
        "username": user.username,
        "gender": {
            "val": user.gender.val,
        },
    });
    // 直接传入serde_json::Value,无需转成字符串
    client
        .execute("INSERT INTO users (user_report) VALUES ($1)", &[&user_json])
        .await?;
    Ok(())
}

进阶优化(直接传入自定义结构体)

如果你的Report结构体已经通过#[derive(Serialize)]实现了序列化,可以直接将结构体转换为serde_json::Value后传入,简化代码:

// 确保Report结构体添加了Serialize派生
#[derive(Serialize)]
struct Report {
    username: String,
    gender: Gender,
}

#[derive(Serialize)]
struct Gender {
    val: String,
}

async fn insert_values(client: &Client, user: &Report) -> Result<(), Error> {
    let user_json = serde_json::to_value(user)?;
    client
        .execute("INSERT INTO users (user_report) VALUES ($1)", &[&user_json])
        .await?;
    Ok(())
}

关键说明

  • tokio-postgres的with-serde_json-1特性已经为serde_json::Value实现了与PostgreSQL JSONB类型的自动转换,不需要手动处理字符串序列化
  • 避免使用unwrap()处理序列化错误,改用?将错误向上传播,提升代码健壮性

内容的提问来源于stack exchange,提问作者Bumin Qagan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 03:11:06