前言:
Mysql
常用的引擎有MYISAM
和InnoDB
,而InnoDB
是Mysql5.1
版本之后默认的引擎(之前是MYISAM
),MYISAM
不支持行锁,而InnoDB
支持行锁和表锁(当然还有很多异同点)
目录
- 行锁和表锁
- 行锁的类型
- 行锁的实现
1. 行锁和表锁
在Mysql的InnoDB引擎支持行锁,与Oracle不同,mysql的行锁是通过索引加载的,即行锁是加在索引响应的行上的,要是对应的SQL语句没有走索引,则会全表扫描,行锁就无法实现取而代之的是表锁。
表锁: 不会发生死锁,发生锁冲突几率高,并发低
行锁: 会出现死锁,发生锁冲突几率低,并发高
- 锁冲突:事物A将某几行上锁后,事物B又对其上锁,锁不能共存否则会导致锁冲突(共享锁可以共存,共享锁和排他锁不能共存,排他锁和排它锁也不能)
- 死锁:事物A锁住了1-5行,同时事物B锁住了6-10行,此时事物A请求锁住6-10,就会堵塞直到事物B释放6-10行锁,事物B请求锁住1-5,事物B也堵塞直到事物A释放1-5行锁,死锁发生时会产生DeadLock错误。
ps:锁是对表操作的,所以自然锁住全表就不会出现死锁。
2. 行锁的类型
行锁分共享锁和排它锁(也称之为读锁和写锁)
- 共享锁(读锁):共享锁可以与共享锁共存,都是读又不写。当一个事物对某几行上读锁时,允许其他事物对着几行进行读操作,但是不允许写操作也不允许其他事物给这几行上排它锁,但是允许上读锁。
- 排它锁(写锁):当一个事物对某几个上写锁时,不允许其他事物写,但允许读。更不允许其他事物给这几行上任何锁。
共享锁的写法:lock in share mode
如:select math from red_envelope where num>60 lock in share mode;
排它锁的写法:for update
如:select math from red_envelope where num>60 for update;
3. 行锁的实现
- 行锁必须有索引才能实现,否则会自动锁全表,那么久不是行锁了。
- 两个事物不能锁同一个索引,例如:
事物A先执行 select math from red_envelope where num>60 for update;
事物B再执行 select math from red_envelope where num<60 for update;
这样的话,事物B是堵塞的。如果事物B把math索引换成其他索引就不会堵塞INSERT、DELETE、UPDATE
在事物中都会自动默认加上排它锁
会话1 | 会话2 |
---|---|
begin;select math from red_envelpe where math>60 for update; | begin;update red_envelope set math=99 where math=68;堵塞··· |
会话相当于用户的操作:
如上表:会话1先把math>60的行上上排它锁,会话2试图把math=68的行进行修改,math=68处于math>60中,所以是已经被锁的,会话2操作时就会堵塞等待会话1把锁释放,当commit或者程序结束时就会释放锁。
网友评论