Golang、database/sql、Postgres - 当您需要结果时,使用 QueryRow 和 INSERT 是不好的做法吗?

jor*_*man 2 sql postgresql go

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

mko*_*iva 5

该指南(顺便说一句,它不是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)