使用准备好的语句(prepared statement)

本文翻译自《Using prepared statements》。

目录

什么是准备好的语句?

如何使用准备好的语句

准备好的语句的行为

你可以定义准备好的语句以供重复使用。这可以避免每次代码执行数据库操作时重新创建语句的额外开销,从而帮助你的代码运行得更快一些。

注意:准备好的语句中的参数占位符因你使用的DBMS和驱动程序而异。例如Postgres的pq驱动程序需要$1形式的占位符,而不是?号占位符。

什么是准备好的语句?

准备好的语句是由DBMS解析和保存的SQL,通常包含占位符但没有实际参数值。稍后,可以使用一组参数值来执行该语句。(译者注:准备好的语句,准备语句,也叫预处理语句。)

如何使用准备好的语句

当你希望重复执行同一条SQL时,可以使用一个sql.Stmt结构体预先准备好SQL语句,然后按需执行。

以下示例创建一个准备好的语句,从数据库中选择一个特定的专辑(album)的信息。DB.Prepare函数返回一个sql.Stmt结构体,代表给定SQL文本的准备语句。你可以将SQL语句的参数值传递给Stmt.ExecStmt.QueryRowStmt.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提供常用的ExecQueryRowQuery方法来调用语句。有关使用这些方法的更多信息,请参阅查询数据执行不返回数据的SQL语句

但是,由于sql.Stmt已经代表了一条预设的SQL语句,所以它的ExecQueryRowQuery方法只需占位符对应的参数值,省略了SQL文本。

你可以用不同的方式定义一个新的sql.Stmt,这取决于你将如何使用它。

  • DB.PrepareDB.PrepareContext方法创建一个准备好的语句,它可以在事务之外单独执行,就像DB.ExecDB.Query方法一样。
  • Tx.PrepareTx.PrepareContextTx.StmtTx.StmtContext方法创建用于特定事务的准备好的语句。PreparePrepareContext方法使用SQL文本来定义语句。StmtStmtContext方法使用DB.PrepareDB.PrepareContext方法的结果。也就是说,它们将一个非事务的sql.Stmt转换为一个事务的sql.Stmt。
  • Conn.PrepareContext方法从sql.Conn方法创建准备好的语句,表示专用的连接。

当你的代码结束时,请确保调用stmt.Close方法。这将释放可能与其关联的任何数据库资源(例如底层连接)。对于函数中仅作为局部变量的语句,defer stmt.Close()就足够了。

用于创建准备好的语句的函数

DB.Prepare
DB.PrepareContext

准备一个单独执行的语句,或者使用Tx.Stmt方法把它转换为事务中的准备语句。

Tx.Prepare
Tx.PrepareContext
Tx.Stmt
Tx.StmtContext

准备用于特定事务的语句。有关更多信息,请参阅执行事务

Conn.PrepareContext

与专用的连接一起使用。有关更多信息,请参阅管理数据库连接

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注