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实现了与PostgreSQLJSONB类型的自动转换,不需要手动处理字符串序列化- 避免使用
unwrap()处理序列化错误,改用?将错误向上传播,提升代码健壮性
内容的提问来源于stack exchange,提问作者Bumin Qagan
相关产品推荐
相关产品推荐

