来自database/sql json列的json.RawMessage被覆盖

wha*_*ave 3 sql json go

使用嵌入式json的结构获得奇怪的行为.

package main

import (
    "database/sql"
    "encoding/json"
    "fmt"

    _ "github.com/lib/pq"
)

type Article struct {
    Id  int
    Doc *json.RawMessage
}

func main() {
    db, err := sql.Open("postgres", "postgres://localhost/json_test?sslmode=disable")
    if err != nil {
        panic(err)
    }

    _, err = db.Query(`create table if not exists articles (id serial primary key, doc json)`)
    if err != nil {
        panic(err)
    }
    _, err = db.Query(`truncate articles`)
    if err != nil {
        panic(err)
    }
    docs := []string{
        `{"type":"event1"}`,
        `{"type":"event2"}`,
    }
    for _, doc := range docs {
        _, err = db.Query(`insert into articles ("doc") values ($1)`, doc)
        if err != nil {
            panic(err)
        }
    }

    rows, err := db.Query(`select id, doc from articles`)
    if err != nil {
        panic(err)
    }

    articles := make([]Article, 0)

    for rows.Next() {
        var a Article
        err := rows.Scan(
            &a.Id,
            &a.Doc,
        )
        if err != nil {
            panic(err)
        }
        articles = append(articles, a)
        fmt.Println("scan", string(*a.Doc), len(*a.Doc))
    }

    fmt.Println()

    for _, a := range articles {
        fmt.Println("loop", string(*a.Doc), len(*a.Doc))
    }
}
Run Code Online (Sandbox Code Playgroud)

输出:

scan {"type":"event1"} 17
scan {"type":"event2"} 17

loop {"type":"event2"} 17
loop {"type":"event2"} 17
Run Code Online (Sandbox Code Playgroud)

因此文章最终指向同一个json.

难道我做错了什么?

UPDATE

编辑成一个可运行的例子.我正在使用Postgres和lib/pq.

mas*_*ase 5

我遇到了同样的问题,看了很长一段时间后我是否阅读了Scan上的文档

如果参数的类型为*[] byte,则Scan会在该参数中保存相应数据的副本.该副本由调用者拥有,可以无限期地修改和保留.可以通过使用*RawBytes类型的参数来避免副本; 有关其使用的限制,请参阅RawBytes的文档.

如果您使用*json.RawMessage,那么我认为会发生什么,然后扫描不会将其视为*[]字节并且不会复制到其中.所以你在下一个循环中进入内部切片扫描覆盖.

更改扫描以将*json.RawMessage强制转换为*[]字节,以便扫描将值复制到该字节.

    err := rows.Scan(
        &a.Id,
        (*[]byte)(a.Doc),
    )
Run Code Online (Sandbox Code Playgroud)