当Golang程序在执行数据库事务时终止时,它可以回滚吗?

时间:2018-12-04 03:58:02

标签: mysql go transactions

假设Lambda函数在三秒钟之后执行后终止,则假定具有默认设置的MariaDB兼容数据库(AWS Aurora RDS)已启用自动提交超过 5秒,例如

  tx, err := h.db.Begin()
  if err != nil {
      log.WithError(err).Error("failed to start transaction")
  }
  res, execErr := tx.Exec(fmt.Sprintf("UPDATE testtable SET val = %d WHERE id = 1; SELECT SLEEP(5.5);", time.Now().Unix()))
  if execErr != nil {
      log.WithError(err).Error("rolling back")
      err = tx.Rollback()
      if err != nil {
          log.WithError(err).Error("failed to roll back")
      }
  }
  if err := tx.Commit(); err != nil {
      log.WithError(err).Error("failed to commit")
  }

假设结果是什么?交易会不会提交?

我正在使用Go MySQL Driver v1.3.0-84-g6be42e0 btw。我也做了一个video showing my results,但是我不知道driver could have executed rollback是怎么回事,所以我想知道这是否正确。

2 个答案:

答案 0 :(得分:1)

事务SQL不提交。我相信会在<= 5秒的超时时间内发生:

  1. BEGIN的交易
  2. 同步执行SQL
  3. MySQLd检测到客户端通过 TCP FIN
  4. 断开了连接
  5. MySQLd自动回滚,因为它没有看到Commit

Golang MySQL driver个维护者之一的推特回复:

Go客户端终止时,mysqld会收到TCP FIN数据包。
即使Go客户端异常退出,OS(Linux内核等)也会发送TCP FIN或TCP RST。这样mysqld可以知道客户端不见了。

— INADA Naoki(@甲烷)December 4, 2018

答案 1 :(得分:0)

如果您使用InnoDB表,请从https://dev.mysql.com/doc/internals/en/transactions-life-cycle.html中进行阅读:

  

关闭连接后,当前的正常事务(如果有)将回滚。

这与Go客户端,Java客户端,PHP客户端或任何其他客户端相同。

如果使用MyISAM表,则不会回滚。如果您当前正在执行SQL更新,则它可能会更新部分行,而其余部分保持不变。您最终将获得一个处于不一致状态的表。非事务表没有ACID行为。 这就是为什么您不应该使用MyISAM。