Go语言中database/sql包操作MySQL(使用预先准备的语句)

准备好的陈述和连接

在数据库级别,准备好的语句绑定到单个数据库连接。典型的流程是客户端向服务器发送带占位符的SQL语句以供准备,服务器用语句ID作出响应,然后客户端通过发送其ID和参数来执行语句。

然而,在Go中,连接并不直接暴露给database/sql的用户 你不准备在连接上发表声明。你准备在一个DB或一个Txdatabase/sql具有一些便利行为,例如自动重试。由于这些原因,准备好的语句和连接之间的基础关联(存在于驱动程序级别)对于您的代码而言是隐藏的。

以下是它的工作原理:

  1. 当您准备一份声明时,它将在池中的一个连接上准备好。
  2. Stmt对象记住使用了哪个连接。
  3. 当你执行时Stmt,它会尝试使用连接。如果因为关闭或忙于做其他事情而无法使用,则它会从池中获得另一个连接,并将语句与另一个连接上的数据库重新进行准备。

由于在原始连接繁忙时将根据需要重新编写语句,因此可能会导致数据库的高并发使用率(可能使大量连接繁忙)创建大量预准备语句。这可能会导致明显的语句泄露,正在准备和重新准备的语句比您想象的更频繁,甚至会遇到服务器端语句数量限制。

避免准备好的陈述

Go会在封面上为您创建准备好的语句。db.Query(sql, param1, param2)例如,一个简单的 工作是准备sql,然后使用参数执行它,最后关闭语句。

但是,有时准备好的声明不是你想要的。这可能有几个原因:

  1. 数据库不支持预准备语句。例如,在使用MySQL驱动程序时,您可以连接到MemSQL和Sphinx,因为它们支持MySQL有线协议。但他们不支持包含预准备语句的“二进制”协议,因此它们可能会以混乱的方式失​​败。
  2. 这些语句没有足够的重用来使它们值得,并且以其他方式处理安全问题,所以性能开销是不希望的。

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

准备交易报表

在a中创建的准备Tx好的语句仅限于它,因此早期有关重新编制的警告不适用。当你在一个Tx对象上进行操作时,你的动作直接映射到它的唯一连接。

这也意味着在一个内部创建的准备语句Tx不能单独使用。同样,在a上创建的准备语句DB也不能在事务中使用,因为它们将被绑定到不同的连接。

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

在处理交易中的预先准备的报表时,必须谨慎行事。考虑下面的例子:

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() runs here!

在Go 1.4关闭一个已*sql.Tx释放的与它关联的连接回到池中之前,但在已准备好的语句中延迟调用Close 以便在发生执行 ,这可能会导致并发访问基础连接,从而导致连接状态不一致。如果您使用Go 1.4或更早版本,则应确保在事务提交或回滚之前语句始终关闭。此问题已在CR 131650043的 Go 1.4中修复

参数占位符语法

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

MySQL               PostgreSQL            Oracle
=====               ==========            ======
WHERE col = ?       WHERE col = $1        WHERE col = :col
VALUES(?, ?, ?)     VALUES($1, $2, $3)    VALUES(:val1, :val2, :val3)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值