MySQL事务(2)
Posted by 付辉 on Thursday, February 28, 2019 共922字
花繁柳密能拨开方见手段,风狂雨骤时可立定才是脚跟。
引言
在MySQL
处理事务的过程中,遇到如下报错:
Error 1205: Lock wait timeout exceeded; try restarting transaction
结合日志信息,很快的定位了问题代码并做了修复,但这个报错却一直存在。观念里,只要等待一段时间,这个错误就应该消失啊,是哪里出问题了?
问题
代码在执行Begin
之后,处理到某个逻辑直接return
处理,没有关闭事务导致的。因为SQL
操作的记录一直占着锁得不到释放,所以后续对该行记录进行写操作时,就会报这个错误。示例代码如下:
func (notify *Sign) HandleSign(ctx *context.Context) error {
// 事务操作,开启事务
if err := ses.Begin(); err != nil {
return err
}
// 这里需要特别注意,正常情况必须加上
// defer ses.Close()
// 更新Log表记录
_, err := ses.Where("id = ?", contractLog.Id).Cols("status").Update(contractLog)
if err != nil {
ses.Rollback()
return err
}
//这个地方直接return导致的,这个事务没有关闭,导致上面的锁一直没有释放
return nil
if err := ses.Commit(); err != nil {
return err
}
ses.Close()
}
问题的关键就在于Begin
后,没有执行Rollback
或Commit
,导致事务没有被关闭。这里特别强调defer close()
的作用,下面是文档对Close
的注释。
Close release the connection from pool
When Close be called, if session is a transaction and do not call Commit or Rollback, then call Rollback
PROCESSLIST
SHOW [FULL] PROCESSLIST
使用如上命令,查看是否存在一个线程执行占用了很长的时间,这体现在它Sleep
的时间上。果不其然,确实有那么一个,但我忍住没有KILL
它。因为我无法确定就是这个线程导致的。
SHOW PROCESSLIST
shows which threads are running. If you have thePROCESS
privilege, you can see all threads. Otherwise, you can see only your own threads (that is, threads associated with the MySQL account that you are using). If you do not use theFULL
keyword, only the first 100 characters of each statement are shown in theInfo
field.
SHOW ENGINE INNODB STATUS
SHOW ENGINE INNODB STATUS
displays extensive information from the standardInnoDB
Monitor about the state of theInnoDB
storage engine. For information about the standard monitor and otherInnoDB
Monitors that provide information aboutInnoDB
processing, see Section 15.16, “InnoDB Monitors”.
一上来就引用SHOW ENGINE Syntax
也是因为没有接触过这个命令,网上说:当你更新表中的某条记录时,如果一些别的线程对这条记录上了锁,并且执行占用时间较长的话,就会导致你对该条记录的操作超时。
不过非常遗憾,我查看了它输出的结果,并没有显示出这条问题SQL
。
innodb_lock_wait_timeout
show variables like 'innodb_lock_wait_timeout';
当事务没有被释放时,后续事务执行失败的等待时间就是由这个设置决定的。当事务访问这条记录超过这个时间还无法获得锁,就会报引言中的错误。
The length of time in seconds an
InnoDB
transaction waits for a row lock before giving up. The default value is 50 seconds. A transaction that tries to access a row that is locked by anotherInnoDB
transaction waits at most this many seconds for write access to the row before issuing the following error
参考文章: