1. 表级锁、行级锁
MyISAM 默认是表级锁,不支持行级锁。 不支持事务
InnoDB 默认是行级锁,也支持表级锁。支持事务,并支持自动提交。
所以 InnoDB 在锁的粒度上更细一点。
2. 悲观锁和乐观锁
乐观锁和悲观锁是一个并发控制的思想,不是数据库系统的专属应用场景。悲观是意思是假设目前很多人抢资源环境不好,乐观则相反。用带隔间的澡堂来比喻吧,现在有一栋大楼,你是个悲观的人,认为所有人都会来洗澡,所以洗澡的时候锁门。假如你是个乐观的人,认为没什么人洗澡,洗澡的时候大门敞开,很自在。
2.1 悲观锁
悲观锁的思想是把共享资源加上锁,至于加锁后其他事务是否允许加锁可分为:
2.1.1 悲观锁 —— 共享锁
我关门洗澡了,你可以看我洗,但是不能跟我一起洗。
- 告诉其他事务,这个数据我就要现在最新的,需要读的可以读,要写的等我用完再写。
2.1.2 悲观锁 —— 排它锁
我关门洗澡了,你看都不能看。
- 告诉其他事务,这个数据我就要现在最新的,并且我要写数据,等我忙完你们才可以读写。
2.2 乐观锁
乐观锁本质上不阻塞进程,会把操作都记录下来,提交前检查是否符合一致性,不符合就放弃、重试、或抛异常
这个在事务的隔离级别会提到这个用法。暂时不讨论。
3. MySQL中的共享锁和排它锁
3.1 MyISAM
-
默认情况 :select、insert 、delete、update
select 默认上读锁,其他上写锁。 -
共享锁又叫读锁
当session A 对表进行 select 范围查询时被加上读锁,此时session B 的读操作(也同时加读锁)并不阻塞。 -
排它锁又叫写锁
当表加上了读锁或者写锁,需要等待它们释放才能加上新的写锁。 -
select操作时,锁的触发
MyISAM 对table进行 select 操作,会自动用表锁锁住整个表,其他 session 对 table 的 insert 、delete、update都会被阻塞。这个表锁更细化来说应该是表级读锁
3.2 InnoDB
由于InnoDB支持事务,并且事务可以关闭自动提交,所以支持二段锁(加锁 + 解锁)
// 关闭当前session的自动提交
set autocommit = 0;
-
默认情况:select、insert 、delete、update
select默认是非阻塞读(不上锁),其他默认上行级写锁两个session上锁可以细化到行级锁,session A 给 id = 1的记录上了行级读锁,session B 写 id = 2 的记录不会阻塞 ,同时给 id = 2 的记录上了行级写锁
// session A select * from table where id = 1 lock in share mode // session B update table set a = "hi" where id = 2
-
读锁、写锁叠加规则
与MyISAM 相同
4. 两者相同 select 加 读锁 / 写锁的规则
- lock in share mode
加读锁,(myisam select 默认是读锁, innoDB select 默认不加锁,默认读的是快照) - for update
加写锁
5. MyISAM和InnoDB适合的场景
MyISAM
- 频繁执行全表count语句
- 对数据增删改不频繁、查询较为频繁
- 不支持事务
InnoDB
- 增删改查都很频繁
- 可靠性要求比较高,需要支持事务
6. 后记
MySQL的读锁如果加得过长,会因为可重入(排队加了写锁和读锁),形成一个读锁 -> 写锁 -> 读锁的链条,容易出现死锁。
相关:生产环境的死锁发现及解决