为什么这个用于sqlx的复制语句卡住了?

huangapple go评论102阅读模式
英文:

Why is this copyin statement for sqlx hanging?

问题

我写了一个玩具应用程序,用于通过sqlx使用Postgresql进行实验。我使用了pq.CopyIn作为准备语句的内容来实现批量插入。

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

然后,我会添加要插入的行到正在创建的批量插入中。

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

最后执行准备好的语句。

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(..., ..., ...)

另外,与问题无直接关联的另一个错误是,在将联系人数组插入到Contacts结构体的Contacts字段时:

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

应该将Contacts字段的指针传递给dbSelect方法,像这样:

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

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

英文:

I've written a toy app to experiment with using Postgresql through sqlx. I got a mass insert working using

pq.CopyIn

as content of a prepared statement

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

I would then proceed to add rows to the mass insert I'm creating.

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

then finally execute the prepared statement

stmt.Exec()

This worked perfectly before, but now I've come back to it and try and execute this code, it hangs on the

stmt.Exec

Am I missing something in my code or is this all to do with the Database Engine, being unresponsive.

Here's my full code for this.

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

I could include the contents of the contacts.json file as well, if that will help.

UPDATE

Yes it was obvious in the end. I was creating a statement from tx,

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

and further additions to this should be to stmt

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

Also another error not directly related to the question is where I insert an array of contacts into the Contacts field of the struct Contacts

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

should be passing a pointer to the Select method of db of the Contacts array field of Contacts, like so

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

In case people try and run this code later and wonder why it's not printing the results to the console.

答案1

得分: 2

根据https://godoc.org/github.com/lib/pq中的"批量导入"部分,应该是这样的:

stmt.Exec(contact.First_name, contact.Last_name, contact.Email)
英文:

From Bulk imports part in https://godoc.org/github.com/lib/pq, it should be

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

huangapple
  • 本文由 发表于 2016年11月2日 19:50:59
  • 转载请务必保留本文链接:https://go.coder-hub.com/40379276.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定