锁是计算机协调多个进程或线程并发访问某一资源的机制。使用锁可以对有限的资源进行保护,解决隔离和并发的矛盾。
锁的分类
- 按照数据的操作类型划分
读锁(共享锁):针对同一份数据,多个读操作可以同时进行而不会相互影响
写锁(排它锁):当前写操作没有完成之前,会阻断其它写锁和读锁 - 按照细粒度划分
表锁
行锁
表锁
偏向MYISAM存储引擎,开销小,加锁快,无死锁,锁定粒度大,发生锁冲突的概率最高,并发度最低。
加表锁语法:
LOCK TABLE <tablename> READ|WRITE[,<tablename2> READ|WRITE...];
去表锁语法:
UNLOCK TABLES;
查看表加的锁:
SHOW OPEN TABLES;
表读锁读写情况
- 不同session都可读取当前表加锁数据
- 当前session尝试修改表数据会报错
- 其它session尝试修改表数据会被阻塞,直到表读锁解除
执行上图语句后,语句下会有光标一直在闪,表示被阻塞。
解除表读锁后,若抢到修改的资格后,就会执行修改操作。
- 当前session读取其它非加锁表数据会报错
- 其它session读取非加锁表数据可正常读取
表写锁读写情况
- 当前session可读写加锁表数据
- 其它session读写加锁表数据会被阻塞
- 当前session读写其它非加锁表数据会报错
- 其它session可正常读取非加锁数据
行锁
偏向InnoDB存储引擎,开销大,加锁慢,会出现死锁,锁定粒度最小,发生锁冲突的概率最小,并发度最高。
行锁是与事务相关联的,说明加行锁之后的数据读情况是与设置的事务级别相一致的。
当修改数据时,MySQL会自动为修改的行加行锁。
- 当前session可修改加行锁数据
- 其它session修改加行锁数据会被阻塞
- 其它session可正常修改非加锁行数据
索引失效行锁变表锁
示例:
b列是varchar类型,现在使用int赋值,没加单引号,会导致索引失效
现在在其他session更改其它非加锁行数据:
我们发现操作被阻塞了,也就是说锁变成了表锁。
间隙锁
当使用范围条件修改数据是,MySQL会为所有符合条件的数据加锁,无论数据是否实际存在表中。
示例:
表中数据如下:
现在我们把1至3的b列都改为xxx
然后在其他session中插入a为2 的一行数据
从上面的显示我们发现操作被阻塞了,但实际上表中是没有a=2这行数据的。也就是说a=2这行并不实际存在的行也被加锁了,这种情况就称为间隙锁。
如何锁定一行
语法:
<SELECT语句> for update;