本文翻译自《Using prepared statements》。
目录
你可以定义准备好的语句以供重复使用。这可以避免每次代码执行数据库操作时重新创建语句的额外开销,从而帮助你的代码运行得更快一些。
注意:准备好的语句中的参数占位符因你使用的DBMS和驱动程序而异。例如Postgres的pq驱动程序需要$1
形式的占位符,而不是?
号占位符。
什么是准备好的语句?
准备好的语句是由DBMS解析和保存的SQL,通常包含占位符但没有实际参数值。稍后,可以使用一组参数值来执行该语句。(译者注:准备好的语句,准备语句,也叫预处理语句。)
如何使用准备好的语句
当你希望重复执行同一条SQL时,可以使用一个sql.Stmt
结构体预先准备好SQL语句,然后按需执行。
以下示例创建一个准备好的语句,从数据库中选择一个特定的专辑(album)的信息。DB.Prepare
函数返回一个sql.Stmt
结构体,代表给定SQL文本的准备语句。你可以将SQL语句的参数值传递给Stmt.Exec
、Stmt.QueryRow
或Stmt.Query
方法以运行该语句。
// AlbumByID函数返回一个特定的专辑(album)的信息。
func AlbumByID(id int) (Album, error) {
// 定义准备好的语句。你通常会在别处定义该语句并将其保存以供在诸如本函数之类的函数中使用。
stmt, err := db.Prepare("SELECT * FROM album WHERE id = ?")
if err != nil {
log.Fatal(err)
}
var album Album
// 执行准备好的语句,为占位符为?的参数传入一个id值。
err := stmt.QueryRow(id).Scan(&album.ID, &album.Title, &album.Artist, &album.Price, &album.Quantity)
if err != nil {
if err == sql.ErrNoRows {
// 处理没有一行数据返回的情况。
}
return album, err
}
return album, nil
}
准备好的语句的行为
准备好的sql.Stmt
提供常用的Exec
、QueryRow
和Query
方法来调用语句。有关使用这些方法的更多信息,请参阅查询数据和执行不返回数据的SQL语句。
但是,由于sql.Stmt
已经代表了一条预设的SQL语句,所以它的Exec
、QueryRow
、Query
方法只需占位符对应的参数值,省略了SQL文本。
你可以用不同的方式定义一个新的sql.Stmt
,这取决于你将如何使用它。
DB.Prepare
和DB.PrepareContext
方法创建一个准备好的语句,它可以在事务之外单独执行,就像DB.Exec
和DB.Query
方法一样。Tx.Prepare
、Tx.PrepareContext
、Tx.Stmt
和Tx.StmtContext
方法创建用于特定事务的准备好的语句。Prepare
和PrepareContext
方法使用SQL文本来定义语句。Stmt
和StmtContext
方法使用DB.Prepare
或DB.PrepareContext
方法的结果。也就是说,它们将一个非事务的sql.Stmt
转换为一个事务的sql.Stmt。Conn.PrepareContext
方法从sql.Conn
方法创建准备好的语句,表示专用的连接。
当你的代码结束时,请确保调用stmt.Clos
e方法。这将释放可能与其关联的任何数据库资源(例如底层连接)。对于函数中仅作为局部变量的语句,defer stmt.Close()
就足够了。
用于创建准备好的语句的函数
DB.Prepare
DB.PrepareContext
准备一个单独执行的语句,或者使用Tx.Stmt
方法把它转换为事务中的准备语句。
Tx.Prepare
Tx.PrepareContext
Tx.Stmt
Tx.StmtContext
准备用于特定事务的语句。有关更多信息,请参阅执行事务。
Conn.PrepareContext
与专用的连接一起使用。有关更多信息,请参阅管理数据库连接。