数据库操作语句大全(sql) 6. 使用准备好的语句

准备好的语句具有 Go 的所有常见优点:安全、高效、方便。 但它们的实现方式可能与您习惯的不同,尤其是它们与数据库/sql的一些内部组件交互的方式。

准备好的语句和连接

在数据库级别,准备好的语句绑定到单个数据库连接。 典型的流程是客户端发送一条带有占位符的SQL语句到服务器进行预处理,服务器响应语句ID,然后客户端通过发送语句ID和参数来执行该语句。

然而,在Go中,连接并不直接暴露给database/sql包的用户。 您不需要为连接做语句准备。 您可以在 DB 或 Tx 上执行此操作。 并且database/sql包中有一些方便的行为,比如自动重试。 由于这些原因,驱动程序级别上存在的准备好的语句和连接之间的底层关联对您的代码是隐藏的。

它的工作原理如下:

当您准备一条语句时数据库操作语句大全(sql),它是在池中的连接上准备的。 Stmt 对象会记住使用了哪个连接。 当您执行 Stmt 时,它会尝试使用该连接。 如果由于关闭或忙于执行其他操作而不可用,它将从池中获取另一个连接,并使用数据库重新准备另一个连接上的语句。

由于在原始连接繁忙时会根据需要重新准备语句,因此数据库的高并发使用会导致大量繁忙连接,从而创建大量准备好的语句。 这可能会导致严重的语句泄漏,准备和重新准备语句的频率比您想象的要高,甚至会达到服务器端语句数量的限制。

避免准备好的语句

数据库中操作语句包括哪些_数据库操作语句大全(sql)_sql语言操作对象和操作结果

Go 在幕后为您创建准备好的语句。 例如,一个简单的 db.Query(sql, param1, param2) 的工作原理是预处理 sql,然后使用参数执行它数据库操作语句大全(sql),最后关闭语句。

有时准备好的陈述并不是您想要的。 造成这种情况的原因可能有以下几个:

数据库不支持准备好的语句。 例如,使用 MySQL 驱动程序时,您可以连接到 MemSQL 和 Sphinx,因为它们支持 MySQL 有线协议。 但它们不支持包含准备好的语句的“二进制”协议,因此它们可能会以令人困惑的方式失败。 这些语句的重用程度不足以使它们变得有价值,并且安全问题可以通过其他方式处理,因此不需要性能开销。 VividCortex 博客上可以看到这样的示例。

如果您不想使用准备好的语句,则需要使用 fmt.Sprint() 或类似的方法来组装 SQL 并将其作为唯一参数传递给 db.Query() 或 db.QueryRow()。 并且您的驱动程序需要支持纯文本查询执行,这是通过 Execer 和 Queryer 接口在 Go 1.1 中添加的。

事务中的准备语句

在 Tx 中创建的准备好的语句仅与其绑定,因此之前有关重新准备的警告不适用。 当您对 Tx 对象进行操作时,您的操作会直接映射到该对象下的一个且仅一个连接。

这也意味着在 Tx 内创建的准备好的语句不能单独使用。 同样,在数据库上创建的准备好的语句不能在事务中使用,因为它们将绑定到不同的连接。

要在 Tx 中使用在事务外准备的准备好的语句,您可以使用 Tx.Stmt(),它根据在事务外准备的语句创建一个新的特定于事务的语句。 为此,它需要现有的准备好的语句,将连接设置为事务的连接,并在每次执行时重新准备所有语句。 这种行为及其实现都是不可取的,甚至在database/sql源代码中有一个TODO来改进它; 我们建议您不要使用它。

数据库操作语句大全(sql)_数据库中操作语句包括哪些_sql语言操作对象和操作结果

在事务中使用准备好的语句时必须小心。 考虑以下示例:

tx, err := db.Begin()
if err != nil {
    log.Fatal(err)
}
defer tx.Rollback()
stmt, err := tx.Prepare("INSERT INTO foo VALUES (?)")
if err != nil {
    log.Fatal(err)
}
defer stmt.Close() // danger!
for i := 0; i < 10; i++ {
    _, err = stmt.Exec(i)
    if err != nil {
        log.Fatal(err)
    }
}
err = tx.Commit()
if err != nil {
    log.Fatal(err)
}
// stmt.Close()在这里运行!

在 Go 1.4 之前,关闭 *sql.Tx 会将与其关联的连接释放回池中,但在此之后延迟调用关闭准备好的语句,这可能会导致对底层连接的并发访问。 ,导致连接状态不一致。 如果您使用的是 Go 1.4 或更早版本,则应确保在提交或回滚事务之前始终关闭语句。 此问题已在 Go 1.4 中由 CR 131650043 修复。

参数占位符语法

sql语言操作对象和操作结果_数据库操作语句大全(sql)_数据库中操作语句包括哪些

准备好的语句中占位符参数的语法是特定于数据库的。 例如,下面是 MySQL、PostgreSQL 和 Oracle 的比较:

MySQL                PostgreSQL                Oracle
============         ==================        =============
WHERE col = ?        WHERE col = $1            WHERE col = :col
VALUES(?, ?, ?)      VALUES($1, $2, $3)        VALUES(:val1, :val2, :val3)

本文首次出现在 LearnKu.com 网站上。

本翻译仅供学习和交流之用。 转载时请务必注明译者、出处以及本文链接。

我们的翻译工作遵守CC协议。 如果我们的工作侵犯了您的权利,请及时联系我们。

© 版权声明
THE END
喜欢就支持一下吧
点赞168赞赏 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容