
本文介绍如何在 go 语言中通过 `lib/pq` 驱动连接并操作 postgresql 9.4,重点讲解对原生 json 类型的读取与自定义解析方法,包括字符串直接处理和实现 `sql.scanner` 接口的高级用法。
PostgreSQL 9.4 正式引入了功能更完善的 JSONB 类型(相比 9.2 起支持的 JSON 类型,JSONB 支持索引、去重和高效查询),而 Go 生态中最成熟、官方推荐的 PostgreSQL 驱动 —— github.com/lib/pq —— 完全兼容 PostgreSQL 9.4,并能无缝处理 JSON 和 JSONB 字段。默认情况下,pq 将 JSON 列以 []byte 形式返回,Go 标准库可直接将其解码为结构体或 map[string]interface{}。
以下是一个基础示例,展示如何建表、插入及查询 JSON 数据:
-- 在 PostgreSQL 中执行
CREATE TABLE foo (id SERIAL PRIMARY KEY, stuff JSON);
INSERT INTO foo (stuff) VALUES ('{"x": 123, "active": true, "tags": ["go", "pg"]}');package main
import (
"database/sql"
"encoding/json"
"fmt"
"log"
_ "github.com/lib/pq"
)
type Foo struct {
ID int
Stuff json.RawMessage // 推荐:延迟解析,避免提前失败
}
func main() {
db, err := sql.Open("postgres", "user=youruser dbname=testdb sslmode=disable")
if err != nil {
log.Fatal(err)
}
defer db.Close()
rows, err := db.Query("SELECT id, stuff FROM foo LIMIT 1")
if err != nil {
log.Fatal(err)
}
defer rows.Close()
for rows.Next() {
var f Foo
if err := rows.Scan(&f.ID, &f.Stuff); err != nil {
log.Fatal(err)
}
// 方案一:直接解析为 map(适合动态结构)
var data map[string]interface{}
if err := json.Unmarshal(f.Stuff, &data); err != nil {
log.Printf("failed to unmarshal JSON: %v", err)
continue
}
fmt.Printf("Parsed: %+v\n", data) // map[x:123 active:true tags:[go pg]]
// 方案二:解析为强类型结构体(推荐用于已知 schema)
var typedStuff struct {
X int `json:"x"`
Active bool `json:"active"`
Tags []string `json:"tags"`
}
if err := json.Unmarshal(f.Stuff, &typedStuff); err != nil {
log.Printf("failed to unmarshal into struct: %v", err)
continue
}
fmt.Printf("Typed: %+v\n", typedStuff)
}
}⚠️ 注意事项:
- 不要直接将 JSON 字段映射为 string(如原答案中所示),因为 pq 实际返回的是 []byte;若强制声明为 string,虽能工作(Go 会隐式转换),但易掩盖类型不匹配风险,且无法处理 NULL JSON 值(会 panic)。应优先使用 json.RawMessage 或自定义类型。
- 若需频繁操作 JSON 并封装业务逻辑,建议实现 sql.Scanner 和 driver.Valuer 接口,实现透明的序列化/反序列化:
type MyJSON struct {
Data map[string]interface{}
}
func (j *MyJSON) Scan(src interface{}) error {
if src == nil {
j.Data = nil
return nil
}
b, ok := src.([]byte)
if !ok {
return fmt.Errorf("cannot scan %T into MyJSON", src)
}
return json.Unmarshal(b, &j.Data)
}
func (j MyJSON) Value() (driver.Value, error) {
if j.Data == nil {
return nil, nil
}
return json.Marshal(j.Data)
}
// 使用时:
type Foo struct {
ID int
Stuff MyJSON
}✅ 总结:lib/pq 完全支持 PostgreSQL 9.4 的 JSON 功能;推荐使用 json.RawMessage 作为中间载体,结合 json.Unmarshal 按需解析;对复杂场景,可通过实现 Scanner/Valuer 提升代码可维护性与类型安全性。无需额外 ORM,标准 database/sql + lib/pq 即可高效驾驭 JSON 数据。










