摘要:
普通select 语句都不会加锁,底层使用 "快照读" 技术, 快照读就是发生写操作时copy一个数据的新副本,其他读操作read旧版本数据,这里采用 “多数据版本”来实现。
会加锁的特殊select语句:
- select ... lock in share mode
- select ... for update
update、delete 默认加 “排它锁(X)”, insert有概率加 “插入意向锁”(gap锁的一种)
并发 Insert 也有概率出现死锁, InnoDB使用插入意向锁,可以提高插入并发
共享锁(S)
- 共享锁用于锁住数据行只能读,即session1 拿到共享锁,其他session都只能读,不能写
应用场景:在某一时刻,需要清点库存,但是此时其他人也可以清点,但是不允许人修改,
demo: select ... lock in share mode
排它锁(X)
- Update、Delete默认都是加排它锁,禁止任何其他客户端同时 “读写” 锁住的数据行
注意点: select ... for update 会加X锁
自增锁
mysql主键经常会使用AUTO_INCREMENT, 当insert没有指定自增列的值时,系统会自动写入自增的值,此时加“自增锁” ,自增锁是table lock表锁,所以为了控制insert的性能,mysql引入一个配置项:innodb_autoinc_lock_mode
innodb_autoinc_lock_mode 配置项:0、1、2。其中0性能最差,1居中,2最快但是有概率id不连续
意向锁
- 意向锁是表级锁。
- InnoDB为了让表锁和行锁共存而使用了意向锁。它有什么存在的意义呢? 假设这样一种情况,sessionA 使用“X锁”锁定了tableA的一行记录,而sessionB使用表锁lock tableA,此时sessionB想改动A锁住的那条记录,此时没有意向锁的话,就是互相冲突的。 更生动的例子,某个酒楼有10个包间,张三通过客服把1号包间订掉了,其他人就没办法再订该包间了,但是此时李四说要包整个酒楼,客服也允许了。那张三带了10个人去吃饭,李四带了上百人吃饭,张三那一桌的10个人和李四的人就要打架了。
- 上述情况就需要意向锁,张三订了1号包间,那整个酒楼就被上了意向锁,别人要包酒楼,客服看下酒楼有意向锁了,就说不能包酒楼了,但是其他9个包间(行锁)可以使用。这时候有人就要提出问题了,直接酒楼上表锁啊?啥呀你,表锁就是整个表锁住了,其他9个包间都不能订了,还这么赚钱???。所以意向锁就是一种比较弱的表级别的锁。直接表锁 性能差的,所以使用意向锁。
- 总结:意向锁,就是为了解决表中有行锁存在时,不允许同时加表锁,但可以对其他行加锁。
间隙锁 (gap锁)
- 当我们用范围条件而不是相等条件检索数据,并请求共享或排他锁时,InnoDB会给符合条件的已有数据记录的索引项加锁;对于键值在条件范围内但不存在的记录,叫做“间隙(GAP)”,InnoDB也会对这个“间隙”加锁,这种锁机制就是所谓的间隙锁(NEXT-KEY)锁。
- 简单来说就是:在条件范围内,但是记录不存在的这些记录行,被其他事务insert这些不存在的记录时,会产生幻读,或不可控的情况。
- 生活案例: 古惑仔 两个帮派 “洪兴” 和 “东兴” 分别代表两个mysql session。某天,洪兴的陈浩南到铜锣湾店铺收保护费,一共4家店编号为:100,101、108、110 四家店,陈浩南成功了收取了这4家店的保护费,第二天 东兴的乌鸦派人去加盖了一家店铺105。陈浩南再次过来收保护费,他们两个帮派就打起来了,陈浩南说,这条街都是我管的,100~110 的记录ID都是我管的,乌鸦就不爽了,你是扛把子了不起啊,这是我们东兴的店铺。冲突这个时候就产生了,所以 gap锁来帮陈浩南了,当铜锣湾都被陈浩南上了gap锁,100~110的店铺都是陈浩南管理,其他人不得加盖店铺!!!!!
典型死锁案例
session 1 session 2 begin begin update table A set name='A' where id=1 update table B set name='B' where id=3 update table B set name='B' where id=3 update table A set name='A' where id=1 commit commit
上述案例:两个会话互相等待对方释放X锁,直到锁等待超时,发生死锁。