使用嵌入了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))
}
}
输出:
scan {"type":"event1"} 17
scan {"type":"event2"} 17
loop {"type":"event2"} 17
loop {"type":"event2"} 17
所以文章最终指向同一个json。
我做错了吗?
更新
编辑了一个可运行的例子。我正在使用Postgres和lib/pq
。
答案 0 :(得分:5)
我遇到了同样的问题,看了很长一段时间后我是否阅读了关于扫描的文档并且说了
如果参数的类型为* [] byte,则Scan会在该参数中保存相应数据的副本。该副本由调用者拥有,可以无限期地修改和保留。可以通过使用* RawBytes类型的参数来避免副本;有关其使用的限制,请参阅RawBytes的文档。
如果您使用* json.RawMessage,我认为会发生什么,然后扫描不会将其视为* []字节并且不会复制到其中。所以你在下一个循环中进入内部切片扫描覆盖。
更改扫描以将* json.RawMessage强制转换为* []字节,以便扫描将值复制到其中。
err := rows.Scan(
&a.Id,
(*[]byte)(a.Doc),
)
答案 1 :(得分:0)
如果有助于任何人:
我使用masebase anwser在具有jsonb列类型的postgresql db列中插入我的struct的json.RawMessage属性。
您需要做的就是在插入绑定方法中转换:([] byte)(a.Doc)(在我的情况下没有*)。