为什么这个 sqlx 的 copyin 语句挂了?

Why is this copyin statement for sqlx hanging?

我编写了一个玩具应用程序来试验通过 sqlx 使用 Postgresql。我使用

进行了批量插入
pq.CopyIn

作为准备好的语句的内容

stmt, _ := tx.Preparex(pq.CopyIn(tablename, column, column, ...)

然后我将继续向正在创建的批量插入添加行。

tx.Exec(..., ..., ...)

然后最后执行prepared statement

stmt.Exec()

这之前工作得很好,但现在我回到它并尝试执行这段代码,它挂在

stmt.Exec

我是不是在我的代码中遗漏了什么,或者这一切都与数据库引擎有关,没有响应。

这是我的完整代码。

package main

import (
    _ "database/sql"
    "fmt"
    "log"
    "encoding/json"
    "io/ioutil"
    "os"

    "github.com/jmoiron/sqlx"
    "github.com/lib/pq"
)

var schema = `
    CREATE TABLE IF NOT EXISTS contact (
        id Serial,
        first_name text,
        last_name text,
        email text
);`

type Contact struct {
    Id int            `json:"-"`
    First_name string `json:"first_name"`
    Last_name string  `json:"last_name"`
    Email string      `json:"email"`
}

type Contacts struct {
    Contacts []Contact `json:"contacts"`
}

func (c *Contacts) createFromJSON(json_str []byte) error {
    b := []byte(json_str)
    err := json.Unmarshal(b, &c)
    if err != nil {
        log.Fatal(err)
    }

    return err
}

func (c *Contacts) save(db *sqlx.DB) error {
    tx := db.MustBegin()

    stmt, _ := tx.Preparex(pq.CopyIn("contact", "first_name", "last_name", "email"))

    for _, contact := range c.Contacts {
        tx.Exec(contact.First_name, contact.Last_name, contact.Email)

    }

    _, err := stmt.Exec()

    if err != nil {
        log.Fatal(err)
        return err
    }
    err = stmt.Close()
    if err != nil {
        log.Fatal(err)
        return err
    }

    tx.Commit()

    return nil
}

func connect() (*sqlx.DB, error) {
    db, err := sqlx.Connect("postgres", "user=pqgotest dbname=pqgotest sslmode=disable")
    if err != nil {
        log.Fatal(err)
    }

    return db, err
}


func createTables(db *sqlx.DB) {
    db.MustExec(schema)
}


func main() {
    db, err := connect()
    if err != nil {
        os.Exit(1)
    }

    createTables(db)
    contactsJson, e := ioutil.ReadFile("./contacts.json")
    if e != nil {
        fmt.Printf("File error: %v\n", e)
        os.Exit(1)
    }

    tx := db.MustBegin()
    tx.MustExec("DELETE FROM contact")
    tx.Commit()

    contacts := new(Contacts)

    contacts.createFromJSON(contactsJson)

    contacts.save(db)

    people := new(Contacts)
    db.Select(people.Contacts, "SELECT * FROM contact ORDER BY email,id ASC")

    for _, contact := range people.Contacts {
        contact_json, err := json.Marshal(contact)
        if err != nil {
            log.Fatal(err)
            os.Exit(1)
        }
        fmt.Printf("%s\n", contact_json)
    }


}

我也可以包含 contacts.json 文件的内容,如果这有帮助的话。

更新

是的,最后很明显。我正在创建来自 tx 的声明,

stmt, _ := tx.Preparex(pq.CopyIn(tablename, column, column, ...)

对此的进一步补充应该是 stmt

stmt.Exec(..., ..., ...)

另外一个与问题不直接相关的错误是我将一个联系人数组插入到结构联系人的联系人字段中的位置

people := new(Contacts)
db.Select(people.Contacts, "SELECT * FROM contact ORDER BY email,id ASC")

应该传递一个指向Contacts的Contacts数组字段的db的Select方法的指针,像这样

db.Select(&people.Contacts, "SELECT * FROM contact ORDER BY email,id ASC")

以防人们稍后尝试 运行 此代码并想知道为什么它没有将结果打印到控制台。

https://godoc.org/github.com/lib/pq中的Bulk imports部分,应该是

stmt.Exec(contact.First_name, contact.Last_name, contact.Email)