1.mysql有哪些锁?MySQL有3种锁级别:页级、表级和行级。表级锁:开销小,加锁速度快;没有死锁;锁粒度大,锁冲突概率最高,并发度最低。行级锁:开销大,加锁慢;可能会出现死锁;锁粒度最小,锁冲突概率最低,并发度最高。页锁:开销和加锁时间介于表锁和行锁之间;会出现死锁;加锁粒度介于表锁和行锁之间,并发通用算法:下一个KeyLocks锁,同时加锁记录(数据),并在记录前面加GapGap锁,不加锁记录,只记录中的GapRecordlock锁前面记录(锁数据,不是锁Gap),所以实际上Next-KeyLocks=Gap锁+Recordlock锁。2、什么情况下会造成死锁?所谓死锁:是指两个或多个进程在执行过程中因争夺资源而相互等待的现象。它将无法前进。这时候就说系统处于死锁状态或者说系统发生了死锁。这些始终相互等待的进程称为死锁进程。表级锁不会造成死锁。因此,解决死锁的主要方法是针对最常用的InnoDB。死锁的关键在于两个(或多个)Session的加锁顺序不一致。那么对应的解决死锁问题的关键就是:让不同的session依次加锁3.一些常见的死锁案例案例1:需求:将投资资金分成几份,随机分配给借款人。起初,业务程序的思路是这样的:投资人投资后,金额随机分成几份,然后从借款人表中随机抽取几份,然后借款人表中的余额为通过selectforupdate一一更新。抽象就是一个session通过for循环会有如下几条语句:Select*fromxxxwhereid='randomid'forupdate基本上程序启动后很快就会死锁。这可以说是最经典的死锁情况。例如两个用户同时投资,用户A的金额随机分成2份分配给借款人1,用户2B的金额随机分成2份分配给借款人2和1。加锁的顺序不同,死锁当然很严重。很快就会出现。这个问题的改进很简单,一次性锁定所有分配的借款人即可。select*fromxxxwhereidin(xx,xx,xx)forupdatelistvaluesmysqlinin会自动从小到大排序,锁从小到大一个一个加。例如(以下sessionid为主键):Session1:mysql>select*fromt3whereidin(8,9)forupdate;+----+------+------+-------------------+|id|课程|名称|ctime|+----+--------+------+--------------------+|8|WA|f|2016-03-0211:36:30||9|JX|f|2016-03-0111:36:30|+----+--------+-----+--------------------+2rowsinset(0.04sec)Session2:select*fromt3whereidin(10,8,5)forupdate;lockwaiting...其实此时id=10的记录并没有被锁定,而是id=5的记录已经被锁定,锁正在等待id=8的记录。不信请看Session3:mysql>select*fromt3whereid=5forupdate;锁定等待Session4:mysql>select*fromt3whereid=10forupdate;+----+--------+------+--------------------+|id|course|name|ctime|+----+-----+-----+------------------+|10|JB|g|2016-03-1011:45:05|+----+--------+------+----------------------+1rowinset(0.00sec)在其他session中,id=5不能锁定可以,但id=10可以锁定。案例二:在开发中,经常会做这种判断需求:根据字段值(带索引)查询,不存在则插入;否则更新。以id为主键为例,还没有id=22的行Session1:select*fromt3whereid=22forupdate;Emptyset(0.00sec)session2:select*fromt3whereid=23forupdate;Emptyset(0.00sec)Session1:insertintot3values(22,'ac','a',now());Lockwaiting...Session2:insertintot3values(23,'bc','b',now());ERROR1213(40001):Deadlockfoundwhentryingtogetlock;tryrestartingtransactionwhenlockingexistingrows时间(主键),mysql只有行锁。当锁定一个不存在的行时(即使条件是主键),mysql会锁定一个范围(用间隙锁)。锁定范围为:(无限小或小于表中锁定id的最大值,无限大或大于表中锁定id的最小值)如:如果表中已有id为(11,12),thenlock(12,infinity)iftheexistingidinthetableis(11,30)Thenlock(11,30)这个死锁的解决方法是:insertintot3(xx,xx)onduplicatekeyupdate`xx`='XX';使用mysql特定的语法来解决这个问题。因为插入语句是针对主键的,所以无论插入的行是否存在,都只会有行锁。案例三:直接进入场景:mysql>select*fromt3whereid=9forupdate;+----+--------+------+---------------------+|id|课程|名称|ctime|+----+--------+------+--------------------+|9|JX|f|2016-03-0111:36:30|+----+--------+------+----------------------+1rowinset(0.00sec)Session2:mysql>select*fromt3whereid<20forupdate;lockwaitingSession1:mysql>insertintot3values(7,'ae','a',now());ERROR1213(40001):Deadlockfoundwhentryingtogetlock;tryrestartingtransaction这个和case1等类似,但是session1没有按照common出牌从某种意义上说,Session2正在等待Session1的id=9的锁。session2再次持有1到8的锁(注意9到19的范围没有被session2加锁),最后session1插入新行的时候还要等待session2,所以就出现了死锁。这个在业务需求中一般不会出现,因为你锁定了id=9,但是想插入id=7的行,有点跳动,当然要有解决办法,那就是重新组织业务需求,避免这样写。