如果sql事务代码中嵌入了接口调用或文件操作等非数据库交互操作,则整个事务可能会被挂起(接口不工作,等待超时或上传下载大型附件)。
事务中存在慢速查询,导致同一事务中的其他dml无法及时释放占用的行锁,导致行锁等待。
这通常是由于在事务代码中添加for循环引起的。虽然单个sql运行得很快,但是当sql的数量很大时,事务将非常慢。
这种sql很容易让人产生错觉。例如,级联更新,例如更新集。。。哪里。。。in(selectb)不仅占用表a上的行锁,还占用表b上的行锁,当sql长时间执行时,很容易导致表b上的行锁等待。
在极少数情况下,例如存储突然脱机时,sql执行会卡在内核调用磁盘的步骤中,一直等待,事务无法提交。
综上所述,如果事务长时间未提交,并且事务中包含dml操作,则可能会发生行锁定等待,从而导致错误。
对于写入,mysql使用以下表锁定方法:
如果表上没有锁,请对其设置写入锁。否则,将锁请求放入写锁队列。
对于读,mysql使用以下锁定方法:
如果表上没有写锁,请在表上设置读锁。否则,将锁请求放入读锁队列。
释放锁时,写锁队列中的线程可以使用锁,然后是读锁队列中的线程。这意味着,如果一个表上有许多更新,select语句将等待,直到不再有更新为止。
mysql的不同存储引擎代表不同的锁定机制。例如myisam和内存存储引擎采用表级锁;bdb存储引擎采用页级锁,但也支持表级锁;innodb存储引擎支持行级锁也支持表级锁,但默认使用行级锁。
mysql有三级锁:页级、表级和行级。
表级锁:成本低,锁定速度快;无死锁;锁粒度大,锁冲突概率最高,并发性最低。
行级锁:成本高、锁定慢、死锁、最小锁定粒度、锁冲突概率最低、并发性最高。
页锁:表锁和行锁之间的开销和锁定时间是有界的;会发生死锁;锁粒度是有界的,表锁和行锁之间是有界的,并发性一般
所谓死锁<死锁>:是指两个或两个以上进程因争用而互相等待的现象执行过程中的资源。如果没有外力,它们就无法前进,如果系统处于死锁状态或系统出现死锁,这些永远等待对方的进程称为死锁进程。表级锁不会产生死锁。所以死锁的解决方案主要是innodb,这是最常用的一种。
死锁的关键是两个(或更多)会话的锁定顺序不一致。
所以解决死锁问题的关键是使不同的会话按顺序锁定