死锁,其实是一个很有意思,也很有挑战的技术问题,大概每个DBA和部分开发朋友都会在工作过程中遇见过。关于死锁我会持续写一个系列的案例分析,希望能够对想了解死锁的朋友有所帮助。
				
					sess1 
				
			
			
				 
					sess2 
				 
			 | 
		
		
			| 
				 
					begin; 
				 
			 | 
			
				 
					 
				 
			 | 
		
		
			| 
				 
					delete from t8 where b = 1; 
				 
			 | 
			
				 
					begin; 
				 
			 | 
		
		
			| 
				 
					 
				 
			 | 
			
				 
					insert into t8 values (NULL,1); 
				 
			 | 
		
		
			| 
				 
					commit; 
				 
			 | 
			
				 
					 
				 
			 | 
		
		
			| 
				 
					 
				 
			 | 
			
				 
					update t8 set
				
					T2 
				 
			  | 
		
		
			| 
				 
					begin; 
				 
			 | 
			
				 
					begin; 
				 
			 | 
		
		
			| 
				 
					 
				 
			 | 
			
				 
					insert into t7(id,a) values(26,10); 
				 
			 | 
		
		
			| 
				 
					insert into t7(id,a) values(30,10); 
				 
			 | 
			
				 
					 
				 
			 | 
		
		
			| 
				 
					 
				 
			 | 
			
				 
					insert into t7(id,a) values(40,9); 
				 
			 | 
		
	
3.3 死锁日志
	
		- 
			------------------------
 
		 
		- 
			LATEST DETECTED DEADLOCK
		 
		- 
			------------------------
		 
		- 
			2017-09-17 15:15:03 7f78eac15700
		 
		- 
			*** (1) TRANSACTION:
		 
		- 
			TRANSACTION 462308661, ACTIVE 6 sec inserting
		 
		- 
			mysql tables in use 1, locked 1
		 
		- 
			LOCK WAIT 2 lock struct(s), heap size 360, 1 row lock(s), undo log entries 1
		 
		- 
			MySQL thread id 3796966, OS thread handle 0x7f78ead9d700, query id 781045166 localhost root update
		 
		- 
			insert into t7(id,a) values(30,10)
		 
		- 
			*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
		 
		- 
			RECORD LOCKS space id 231 page no 4 n bits 72 index `ua` of table `test`.`t7` trx id 462308661 lock mode S waiting
		 
		- 
			*** (2) TRANSACTION:
		 
		- 
			TRANSACTION 462308660, ACTIVE 43 sec inserting, thread declared inside InnoDB 5000
		 
		- 
			mysql tables in use 1, locked 1
		 
		- 
			4 lock struct(s), heap size 1184, 3 row lock(s), undo log entries 2
		 
		- 
			MySQL thread id 3796960, OS thread handle 0x7f78eac15700, query id 781045192 localhost root update
		 
		- 
			insert into t7(id,a) values(40,9)
		 
		- 
			*** (2) HOLDS THE LOCK(S):
		 
		- 
			RECORD LOCKS space id 231 page no 4 n bits 72 index `ua` of table `test`.`t7` trx id 462308660 lock_mode X locks rec but not gap
		 
		- 
			*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
		 
		- 
			RECORD LOCKS space id 231 page no 4 n bits 72 index `ua` of table `test`.`t7` trx id 462308660 lock_mode X locks gap before rec insert intention waiting
		 
		- 
			*** WE ROLL BACK TRANSACTION (1) 
		
 
	
 
日志分析
我们从时间线维度分析:
T2 insert into t7(id,a) values(26,10)语句insert 成功,持有a=10 的X 行锁(X locks rec but not gap)
T1 insert into t7(id,a) values(30,10),因为T2 的第一条insert已经插入a=10的记录,T1的 insert a=10 则发生唯一约束冲突,需要申请对冲突的唯一索引加上S Next-key Lock (也即是 lock mode S waiting ) 这是一个间隙锁会申请锁住[4,10],[10,20]之间的gap区域。从这里会发现,即使是RC事务隔离级别,也同样会存在Next-Key Lock锁,从而阻塞并发。
T2 insert into t7(id,a) values(40,9) 该语句插入的a=9 的值在 T1申请的gap锁[4,10]之间,故需T2的第二条insert语句要等待T1的S-Next-key Lock锁释放,在日志中显示lock_mode X locks gap before rec insert intention waiting
四 总结 
  首先感谢登博和姜承尧两位德艺双馨的MySQL技术大牛对死锁技术知识的无私分享。本文案例和知识点一方面从官方文档获取,另一方面是根据两位大牛的分享整理,算是站在巨人的肩膀上的学习总结。在研究分析死锁案例的过程中,insert 的意向锁 和 gap 锁这种类型的锁是比较难分析的,相信通过上面的分析总结大家能够学习到 insert的锁机制 ,如何加锁,如何进行 insert 方面死锁分析。
如果各位觉得阅读本文能够有所收获 欢迎 打赏一瓶饮料 
