sql - 来自数据库/sql json 列的 json.RawMessage 被覆盖

标签 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))
    }
}

输出:

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

loop {"type":"event2"} 17
loop {"type":"event2"} 17

因此文章最终指向相同的 json。

我做错了什么吗?

更新

编辑为可运行的示例。我正在使用 Postgres 和 lib/pq

最佳答案

我遇到了同样的问题,看了很长时间后,我阅读了 Scan 上的文档,上面写着

If an argument has type *[]byte, Scan saves in that argument a copy of the corresponding data. The copy is owned by the caller and can be modified and held indefinitely. The copy can be avoided by using an argument of type *RawBytes instead; see the documentation for RawBytes for restrictions on its use.

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

更改您的 Scan 以将 *json.RawMessage 转换为 *[]byte,以便 Scan 将值复制到它。

    err := rows.Scan(
        &a.Id,
        (*[]byte)(a.Doc),
    )

关于sql - 来自数据库/sql json 列的 json.RawMessage 被覆盖,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24069459/

相关文章:

C#在几个月内有所不同?

sql - 使用 db2 在 C 程序中嵌入 SQL

使用 GROUP BY 进行 SQL MERGE

java - Android - 数据未添加到 MySQL 数据库 - 没有错误

go - 不应通过中间件HTTP测试

reflection - 戈朗。在运行时向结构添加属性

mysql - SQL 嵌套 if 在具有存在并检查时间戳的函数内部

java - JSONArray 中的 JSONObject

python - 从 API 访问 JSON 数据

go - 如何嵌入文件以供以后解析执行使用