使用 pgx 和 go 在简单的 postgresql 查询中返回 id
Returning id in simple postgresql query using pgx and go
我正在尝试运行这个简单的查询到returnid,据作者说我们使用了QueryRow函数,ok,但是这个查询结果returns a expects 2 个参数,但在此处某处收到 3 个错误。
querymodel.go
type WidgetetModel struct {
DB *pgxpool.Pool
}
func (m *WidgetModel) Insert(title, content, expires string) (int, error) {
stmt := `INSERT INTO widgets (title, content, created, expires) VALUES(, , NOW(), NOW() + INTERVAL ' day') RETURNING id;`
var id int
err := m.DB.QueryRow(context.Background(), stmt, title, content, expires).Scan(&id)
if err != nil {
if errors.Is(err, sql.ErrNoRows) {
return 0, models.ErrNoRecord
} else {
return 0, err
}
}
return 0, nil
}
handlers.go
func (app *application) createWidget(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
w.Header().Set("Allow", http.MethodPost)
app.clientError(w, http.StatusMethodNotAllowed) // Use the clientError() helper.
return
}
title := "Widget 1"
content := "Some content here..."
expires := "7"
id, err := app.widgets.Insert(title, content, expires)
if err != nil {
app.serverError(w, err) <-- line 57
return
}
http.Redirect(w, r, fmt.Sprintf("/widget?id=%v", id), http.StatusSeeOther)
}
main.go
我只是在此处使用结构体为我的处理程序注入依赖项。
dbPool, err := openDB(*dsn)
if err != nil {
errorLog.Fatal(err)
}
defer dbPool.Close()
app := &application{
errorLog: errorLog,
infoLog: infoLog,
snippets: &postgresql.WidgetModel{DB: dbPool},
}
///
func openDB(dsn string) (*pgxpool.Pool, error) {
pool, err := pgxpool.Connect(context.Background(), dsn)
if err != nil {
return nil, err
}
if err = pool.Ping(context.Background()); err != nil {
return nil, err
}
return pool, nil
}
错误输出
go run ./cmd/web
INFO 2022/02/20 17:19:30 Starting server on :4000
ERROR 2022/02/20 17:19:38 handlers.go:57: expected 2 arguments, got 3
goroutine 34 [running]:
runtime/debug.Stack()
/usr/local/go/src/runtime/debug/stack.go:24 +0x88
main.(*application).serverError(0x1400008e000, {0x1005c7be8, 0x1400009a1c0}, {0x1005bf2c0, 0x14000094120})
/Users/spencerlong/Desktop/Golang/Snippetts/cmd/web/helpers.go:12 +0x44
main.(*application).createSnippet(0x1400008e000, {0x1005c7be8, 0x1400009a1c0}, 0x140000c8000)
/Users/spencerlong/Desktop/Golang/Snippetts/cmd/web/handlers.go:57 +0x200
net/http.HandlerFunc.ServeHTTP(0x14000094020, {0x1005c7be8, 0x1400009a1c0}, 0x140000c8000)
/usr/local/go/src/net/http/server.go:2046 +0x40
net/http.(*ServeMux).ServeHTTP(0x14000092000, {0x1005c7be8, 0x1400009a1c0}, 0x140000c8000)
/usr/local/go/src/net/http/server.go:2424 +0x18c
net/http.serverHandler.ServeHTTP({0x1400009a000}, {0x1005c7be8, 0x1400009a1c0}, 0x140000c8000)
/usr/local/go/src/net/http/server.go:2878 +0x444
net/http.(*conn).serve(0x140000b0000, {0x1005ca280, 0x14000096180})
/usr/local/go/src/net/http/server.go:1929 +0xb6c
created by net/http.(*Server).Serve
/usr/local/go/src/net/http/server.go:3033 +0x4b8
helpers.go
func (app *application) serverError(w http.ResponseWriter, err error) {
trace := fmt.Sprintf("%s\n%s", err.Error(), debug.Stack())
app.errorLog.Output(2, trace)
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
}
根据您收到的错误:
expected 2 arguments, got 3
我怀疑 SQL 引号内的查询中的 </code> 未被解释为参数。另外据我所知,这不是在 postgres 中使用参数间隔的正确方法。正确的方法是写 <code>interval '1 day' *
所以我认为如果您将代码更改为:
stmt := `INSERT INTO widgets (title, content, created, expires) VALUES(, , NOW(), NOW() + INTERVAL '1 day' * ) RETURNING id;`
它会起作用的。但请务必将 expires
参数更改为类型 int。
' day'
您不能将查询参数作为字符串文字的一部分传递。
尝试将所有 INTERVAL ' day'
部分替换为参数。喜欢这个。
func (m *WidgetModel) Insert(title, content, expires string) (int, error) {
stmt := `
INSERT INTO widgets (title, content, created, expires)
VALUES (, , NOW(), NOW() + )
RETURNING id;`
var id int
expiresDays, err := strconv.ParseInt(expires, 10, 32)
if err != nil {
return 0, err
}
expiresInterval := pgtype.Interval{
Days: int32(expiresDays),
Status: pgtype.Present}
err = m.DB.QueryRow(context.Background(), stmt, title, content,
expiresInterval).Scan(&id)
if err != nil {
if errors.Is(err, sql.ErrNoRows) {
return 0, models.ErrNoRecord
} else {
return 0, err
}
}
return 0, nil
}
我正在尝试运行这个简单的查询到returnid,据作者说我们使用了QueryRow函数,ok,但是这个查询结果returns a expects 2 个参数,但在此处某处收到 3 个错误。
querymodel.go
type WidgetetModel struct {
DB *pgxpool.Pool
}
func (m *WidgetModel) Insert(title, content, expires string) (int, error) {
stmt := `INSERT INTO widgets (title, content, created, expires) VALUES(, , NOW(), NOW() + INTERVAL ' day') RETURNING id;`
var id int
err := m.DB.QueryRow(context.Background(), stmt, title, content, expires).Scan(&id)
if err != nil {
if errors.Is(err, sql.ErrNoRows) {
return 0, models.ErrNoRecord
} else {
return 0, err
}
}
return 0, nil
}
handlers.go
func (app *application) createWidget(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
w.Header().Set("Allow", http.MethodPost)
app.clientError(w, http.StatusMethodNotAllowed) // Use the clientError() helper.
return
}
title := "Widget 1"
content := "Some content here..."
expires := "7"
id, err := app.widgets.Insert(title, content, expires)
if err != nil {
app.serverError(w, err) <-- line 57
return
}
http.Redirect(w, r, fmt.Sprintf("/widget?id=%v", id), http.StatusSeeOther)
}
main.go
我只是在此处使用结构体为我的处理程序注入依赖项。
dbPool, err := openDB(*dsn)
if err != nil {
errorLog.Fatal(err)
}
defer dbPool.Close()
app := &application{
errorLog: errorLog,
infoLog: infoLog,
snippets: &postgresql.WidgetModel{DB: dbPool},
}
///
func openDB(dsn string) (*pgxpool.Pool, error) {
pool, err := pgxpool.Connect(context.Background(), dsn)
if err != nil {
return nil, err
}
if err = pool.Ping(context.Background()); err != nil {
return nil, err
}
return pool, nil
}
错误输出
go run ./cmd/web
INFO 2022/02/20 17:19:30 Starting server on :4000
ERROR 2022/02/20 17:19:38 handlers.go:57: expected 2 arguments, got 3
goroutine 34 [running]:
runtime/debug.Stack()
/usr/local/go/src/runtime/debug/stack.go:24 +0x88
main.(*application).serverError(0x1400008e000, {0x1005c7be8, 0x1400009a1c0}, {0x1005bf2c0, 0x14000094120})
/Users/spencerlong/Desktop/Golang/Snippetts/cmd/web/helpers.go:12 +0x44
main.(*application).createSnippet(0x1400008e000, {0x1005c7be8, 0x1400009a1c0}, 0x140000c8000)
/Users/spencerlong/Desktop/Golang/Snippetts/cmd/web/handlers.go:57 +0x200
net/http.HandlerFunc.ServeHTTP(0x14000094020, {0x1005c7be8, 0x1400009a1c0}, 0x140000c8000)
/usr/local/go/src/net/http/server.go:2046 +0x40
net/http.(*ServeMux).ServeHTTP(0x14000092000, {0x1005c7be8, 0x1400009a1c0}, 0x140000c8000)
/usr/local/go/src/net/http/server.go:2424 +0x18c
net/http.serverHandler.ServeHTTP({0x1400009a000}, {0x1005c7be8, 0x1400009a1c0}, 0x140000c8000)
/usr/local/go/src/net/http/server.go:2878 +0x444
net/http.(*conn).serve(0x140000b0000, {0x1005ca280, 0x14000096180})
/usr/local/go/src/net/http/server.go:1929 +0xb6c
created by net/http.(*Server).Serve
/usr/local/go/src/net/http/server.go:3033 +0x4b8
helpers.go
func (app *application) serverError(w http.ResponseWriter, err error) {
trace := fmt.Sprintf("%s\n%s", err.Error(), debug.Stack())
app.errorLog.Output(2, trace)
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
}
根据您收到的错误:
expected 2 arguments, got 3
我怀疑 SQL 引号内的查询中的 </code> 未被解释为参数。另外据我所知,这不是在 postgres 中使用参数间隔的正确方法。正确的方法是写 <code>interval '1 day' *
所以我认为如果您将代码更改为:
stmt := `INSERT INTO widgets (title, content, created, expires) VALUES(, , NOW(), NOW() + INTERVAL '1 day' * ) RETURNING id;`
它会起作用的。但请务必将 expires
参数更改为类型 int。
' day'
您不能将查询参数作为字符串文字的一部分传递。
尝试将所有 INTERVAL ' day'
部分替换为参数。喜欢这个。
func (m *WidgetModel) Insert(title, content, expires string) (int, error) {
stmt := `
INSERT INTO widgets (title, content, created, expires)
VALUES (, , NOW(), NOW() + )
RETURNING id;`
var id int
expiresDays, err := strconv.ParseInt(expires, 10, 32)
if err != nil {
return 0, err
}
expiresInterval := pgtype.Interval{
Days: int32(expiresDays),
Status: pgtype.Present}
err = m.DB.QueryRow(context.Background(), stmt, title, content,
expiresInterval).Scan(&id)
if err != nil {
if errors.Is(err, sql.ErrNoRows) {
return 0, models.ErrNoRecord
} else {
return 0, err
}
}
return 0, nil
}