Go语言中database/sql包操作MySQL(修改数据和使用事务)

修改数据的语句

Exec(),最好用事先准备好的声明,来实现的INSERT, UPDATEDELETE,或其他不返回行的语句。以下示例显示如何插入行并检查有关操作的元数据:

stmt, err := db.Prepare("INSERT INTO users(name) VALUES(?)")
if err != nil {
	log.Fatal(err)
}
res, err := stmt.Exec("Dolly")
if err != nil {
	log.Fatal(err)
}
lastId, err := res.LastInsertId()
if err != nil {
	log.Fatal(err)
}
rowCnt, err := res.RowsAffected()
if err != nil {
	log.Fatal(err)
}
log.Printf("ID = %d, affected = %d\n", lastId, rowCnt)

执行语句会生成一个sql.Result可以访问语句元数据的语句:最后插入的ID和受影响的行数。

如果你不关心结果怎么办?如果你只是想执行一个语句并检查是否有错误,但忽略结果呢?以下两个陈述不会做同样的事情吗?

_, err := db.Exec("DELETE FROM users")  // 推荐
_, err := db.Query("DELETE FROM users") // 不建议用

答案是不。他们不会做同样的事情,你不应该这样使用 Query()Query()会返回sql.Rows,直到它保留了一个数据库连接sql.Rows被关闭。由于可能有未读数据(例如更多数据行),因此无法使用连接。在上面的例子中,连接永远不会再被释放。垃圾收集器net.Conn最终会为您关闭底层,但这可能需要很长时间。此外,database / sql包会持续跟踪其连接池中的连接,希望在某个时候释放连接,以便连接可以再次使用。因此,这种反模式是耗尽资源的好方法(例如,连接太多)。

使用事务

在Go中,事务本质上是一个保留到数据存储的连接的对象。它可以让你完成迄今为止所看到的所有操作,但保证它们将在相同的连接上执行。

你开始一个事务db.Begin(),并用其Commit()Rollback()关闭 方法上产生的Tx变量。在封面下,Tx从池中获取连接,并保留该连接仅用于该事务。Tx地图上的方法一对一地分配给您可以在数据库本身上调用的方法,比如Query()等等。

在事务中创建的已准备语句仅限于该事务。

你不应该混用事务相关的函数,比如Begin() 和Commit()SQL语句,比如BEGINCOMMITSQL代码。坏事可能会导致:

  • 这些Tx对象可以保持打开状态,从池中保留一个连接而不返回它。
  • 数据库的状态可能与代表它的Go变量的状态不同步。
  • 你可能会认为你正在一个事务中的单个连接上执行查询,但实际上Go已经无形地为你创建了多个连接,而某些语句不是事务的一部分。

当你在一个事务中工作时,你应该小心不要调用这个Db变量。将您所有的电话都转到Tx您创建变量上db.Begin()Db不是一个交易,只是一个交易Tx如果您打电话给其他人db.Exec()或类似人员,那么这些情况将会发生在您的交易范围之外,并在其他连接上发生。

如果您需要处理修改连接状态的多条语句,则Tx即使您不希望事务本身也需要一条语句例如:

  • 创建仅对一个连接可见的临时表。
  • 设置变量,比如MySQL的SET @var := somevalue语法。
  • 更改连接选项,如字符集或超时。

如果您需要执行上述任何操作,则需要将您的活动绑定到单个连接,而在Go中执行此操作的唯一方法是使用 Tx

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值