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

SQLx将JsonValue字段始终识别为字符串,如何解决?

问题解决:Sqlx解析Sqlite VARCHAR字段为JsonValue::String而非JSON对象的问题

问题原因

Sqlite本身没有原生JSON类型,sqlx默认会将VARCHAR字段读取为普通字符串,即使存储的内容是JSON格式的字符串,也会直接包装成JsonValue::String,不会自动解析为JSON结构。


解决方案

方案一:查询时用Sqlite JSON函数显式解析

如果你的Sqlite版本≥3.38.0(该版本引入了json()函数),可以在查询语句中直接调用json()函数将字符串转换为JSON对象,让sqlx正确识别并解析为对应类型:

let foo = sqlx::query_as!(Foo, "SELECT json(bar) AS bar FROM foo LIMIT 1")
    .fetch_one(&db)
    .await?;

执行后foo.bar会被解析为Object {},符合预期。

方案二:自定义类型实现数据库转换逻辑

如果不想每次查询都写json(),可以封装一个自定义类型,手动实现从字符串到JsonValue的解析:

use sqlx::{FromSql, Sqlite, SqliteValue};
use serde_json::Value as JsonValue;

#[derive(Debug, Clone, PartialEq)]
pub struct DbJson(pub JsonValue);

// 实现从Sqlite值转换为DbJson
impl FromSql<Sqlite> for DbJson {
    fn from_sql(value: SqliteValue<'_>) -> sqlx::Result<Self> {
        let s = String::from_sql(value)?;
        let json = serde_json::from_str(&s)
            .map_err(|e| sqlx::Error::Decode(e.into()))?;
        Ok(DbJson(json))
    }
}

// 可选:实现写入数据库的逻辑
impl sqlx::ToSql<Sqlite> for DbJson {
    fn to_sql(&self) -> sqlx::Result<sqlx::sqlite::SqliteArgumentValue<'_>> {
        let s = serde_json::to_string(&self.0)
            .map_err(|e| sqlx::Error::Encode(e.into()))?;
        Ok(s.into())
    }
}

修改结构体使用自定义类型:

#[derive(sqlx::FromRow)]
pub struct Foo {
    pub bar: DbJson,
}

使用时通过foo.bar.0访问解析后的JsonValue。

方案三:通过字段属性手动转换

在结构体字段上添加#[sqlx(try_from = "String")]属性,同时为JsonValue实现TryFrom<String>:

use std::convert::TryFrom;
use serde_json::Error as JsonError;

// 为JsonValue实现从String的尝试转换
impl TryFrom<String> for sqlx::types::JsonValue {
    type Error = JsonError;

    fn try_from(s: String) -> Result<Self, Self::Error> {
        serde_json::from_str(&s)
    }
}

修改结构体字段:

#[derive(sqlx::FromRow)]
pub struct Foo {
    #[sqlx(try_from = "String")]
    pub bar: sqlx::types::JsonValue,
}

查询时sqlx会自动尝试将字符串解析为JsonValue,解析失败会返回Decode错误。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 16:41:05