介绍
数据库/sql
在 Go 标准 sql 库中,该*Stmt
类型具有如下定义的方法:
func (s *Stmt) Exec(args ...interface{}) (Result, error)
func (s *Stmt) Query(args ...interface{}) (*Rows, error)
新的(未命名的)语句由以下人员准备:
func (db *DB) Prepare(query string) (*Stmt, error)
- 连接池是抽象的,不能直接访问
- 在单个连接上准备事务
- 如果连接在语句执行时不可用,它将在新连接上重新准备。
pgx
该PreparedStatement
类型没有定义任何方法。一个新的命名准备好的语句由以下人员准备:
func (p *ConnPool) Prepare(name, sql string) (*PreparedStatement, error)
- 操作直接在连接池上
- 事务在池的所有连接上准备好
- 没有明确的方法如何执行准备好的语句
在Github 评论中,作者更好地解释了 pgx 和 database/sql 之间的架构差异。文档Prepare
还指出(强调我的):
准备是幂等的;即使用相同的名称和sql 参数多次调用Prepare 是安全的。这允许准备和查询/执行/PrepareEx 的代码路径,而不用担心语句是否已经准备好。
小例子
package main
import (
"github.com/jackc/pgx"
)
func main() {
conf := pgx.ConnPoolConfig{
ConnConfig: pgx.ConnConfig{
Host: "/run/postgresql",
User: "postgres",
Database: "test",
},
MaxConnections: 5,
}
db, err := pgx.NewConnPool(conf)
if err != nil {
panic(err)
}
_, err = db.Prepare("my-query", "select $1")
if err != nil {
panic(err)
}
// What to do with the prepared statement?
}
问题)
- 这个
name
论点给我的印象是它可以通过调用它来执行name
,但是如何呢? - 该文档给人的印象是
Query
/Exec
方法以某种方式利用了准备好的语句。但是,这些方法不带name
参数。它如何匹配它们? - 据推测,匹配是由查询内容完成的。那么命名语句的全部意义是什么?
可能的答案
这是我自己走多远:
- 没有按名称引用查询的方法(假设)
- 匹配是在
conn.ExecEx()
. 如果它还没有准备好,它将完成:
ps, ok := c.preparedStatements[sql]
if !ok {
var err error
ps, err = c.prepareEx("", sql, nil)
if err != nil {
return "", err
}
}
- PosgreSQL 本身需要它来做某事(假设)。