Go 数据库/sql Postgres 适配器不支持LastInsertId. 来自文档:
pq不支持database/sql中Result类型的LastInsertId()方法。要返回 INSERT(或 UPDATE 或 DELETE)的标识符,请在标准 Query 或 QueryRow 调用中使用 Postgres RETURNING 子句。
但是 Go database/sql 文档建议不要使用它Query来修改数据库,因为它:
保留数据库连接直到 sql.Rows 关闭。由于可能存在未读数据(例如更多数据行),因此无法使用该连接。在上面的示例中,连接将永远不会再次释放。
文档还说“你永远不应该像这样使用 Query() ”。
如果您需要结果行,大多数人建议使用PostgresQueryRow进行操作。INSERT我不完全理解文档给出的技术推理,但它似乎与我读到的内容相冲突。QueryRow使用来做是否安全且被认为是良好的做法INSERT?
该指南(顺便说一句,它不是database/sql文档)并没有错误,但您错过了引用段落上方的片段中的重要部分,请注意评论// BAD:
_, err := db.Query("DELETE FROM users") // BAD
Run Code Online (Sandbox Code Playgroud)
特别注意的是_. 这在 Go 中称为“空白标识符”,它允许您丢弃不关心的值。
调用时,Query您返回一个*sql.Rows实例作为第一个返回值,该值需要在使用完毕后关闭,如果丢弃它,则无法关闭它,如果不关闭它,则会泄漏连接。*sql.Rows通过调用该方法来关闭Close。
当调用QueryRow你返回一个*sql.Row值时,这个值需要在你使用完后关闭,如果你丢弃它,你就无法关闭它,如果你不关闭它,你将泄漏连接。*sql.Row通过调用该方法来关闭Scan。
“使用 QueryRow 执行 INSERT 是否安全且被视为良好实践?”
是的,是的,只要你正确处理返回值。
做这样的事情绝对没问题:
var id int
row := db.QueryRow("insert ... returning id", params...)
if err := row.Scan(&id); err != nil { // scan will release the connection
return err
}
fmt.Println(id)
Run Code Online (Sandbox Code Playgroud)
或者:
rows, err := db.Query("insert ... values (...), (...) returning id", params...)
if err != nil {
return err
}
defer rows.Close() // make sure that the connection is released once the function returns/panics
var ids []int
for rows.Next() {
var id int
if err := rows.Scan(&id); err != nil {
return err
}
ids = append(ids, id)
}
if err := rows.Err(); err != nil {
return err
}
fmt.Println(ids)
Run Code Online (Sandbox Code Playgroud)