
本文介绍在 Go 应用中使用 database/sql 和 pgx/pq 驱动正确更新 PostgreSQL 的 JSONB 列,重点解决因 JSON 字符串转义不当导致的 pq: invalid input syntax for type json 错误。
本文介绍在 go 应用中使用 `database/sql` 和 `pgx`/`pq` 驱动正确更新 postgresql 的 `jsonb` 列,重点解决因 json 字符串转义不当导致的 `pq: invalid input syntax for type json` 错误。
在 Go 中操作 PostgreSQL 的 JSONB 类型字段时,一个常见误区是:直接将普通字符串(如 HTML 片段或含特殊字符的邮箱)作为 jsonb 值传入 jsonb_set() 函数。PostgreSQL 要求 jsonb_set() 的第三个参数必须是合法的 JSONB 值;若传入未加引号的原始字符串(例如 <a href="...">[email protected]</a>),PostgreSQL 会尝试将其解析为 JSON 对象或数组,从而报错 invalid input syntax for type json。
你原代码的问题在于:
jsonb_set("details", '{"UploadBy"}', $1::jsonb, true)此处 $1::jsonb 强制将 Go 传入的字符串(如含 , <code>", / 等字符的 HTML 链接)当作已格式化的 JSONB 解析——但该字符串本身不是合法 JSON(缺少外层双引号、内部引号未转义),因此解析失败。
✅ 正确做法是:让 PostgreSQL 自动将文本安全转换为 JSONB 值,使用内置函数 to_jsonb():
result, err := Db.Exec(`
UPDATE instruction.file
SET details = jsonb_set(details, '{\"UploadBy\"}', to_jsonb($1::text), true)
WHERE id = $2
`, uname, 820) // 注意:id 是整数,建议用 int 类型而非字符串 "820"
if err != nil {
log.Fatal("Update failed:", err)
}? 关键改进说明:
-
to_jsonb($1::text):先将参数作为纯文本(text)传入,再由 PostgreSQL 调用to_jsonb()将其自动转义并封装为合法 JSON 字符串(即等价于'"<a ...>[email protected]</a>"'::jsonb)。 - 路径参数
'{"UploadBy"}'中的双引号需在 SQL 字符串内正确转义(Go 字符串中写为'{\"UploadBy\"}'),或改用美元符号引用($$(UploadBy)$$)提升可读性。 -
id = $2使用整数类型(如820)而非字符串"820",避免隐式类型转换风险。
? 补充建议:
- 若
uname内容始终为字符串(非对象/数组),to_jsonb($1)已足够;无需显式::text,因为to_jsonb()会自动处理。 - 更健壮的写法(支持任意嵌套结构):
// 若需存入 JSON 对象(如 map[string]interface{}),先在 Go 中序列化: data, _ := json.Marshal(map[string]string{"UploadBy": uname}) _, err := Db.Exec(`UPDATE instruction.file SET details = jsonb_set(details, $1, $2::jsonb, true) WHERE id = $3`, []string{"UploadBy"}, data, 820) - 始终校验
RowsAffected()并处理err,确保业务逻辑一致性。
通过 to_jsonb() 替代手动类型强转,既规避了 JSON 语法错误,又提升了代码安全性与可维护性。


















