一、介绍
MySQL的锁主要为:
- 全局锁
- 表锁
- 行锁
二、全局锁
全局锁分为:
- 读锁(共享锁):允许别人读取数据,不允许更新数据
- 写锁(排它锁):不允许别人读取和更新数据
使用场景:进行一些需要确保整个数据库一致性的操作,例如全库备份、全库导出等
添加锁语句:FLUSH TABLES WITH READ LOCK
释放锁语句:UNLOCK TABLES
三、表锁
特点:开销小,加锁快,不会出现死锁。锁定粒度大,发生锁冲突的概率最高,并发度最低。
InnoDB引擎在必要情况下会使用表锁,但主要是使用行锁来实现多版本并发控制(MVCC),它能提供更好的并发性能和更少的锁冲突
1、使用场景
- 读多写少:因为表级读锁不会阻塞其他的读锁,所以这种场景下表锁能够提供很高的性能
- 数据量少:由于数据量少,那么即使在写操作中,由于锁定整张表,对性能的影响也不大
- 全表更新/删除:例如更新表中所有记录的某个字段的值,或删除表中的所有记录,那么使用表级锁是最合适的
2、MySQL哪些命令会发生表级锁
- ALTER TABLE
- DROP TABLE/TRUNCATE TABLE
- LOCK TABLES:如
LOCK TABLES t1 WRITE, t2 READ
- 全表扫描/大范围扫描:针对MyISAM存储引擎,全局扫描/大范围扫描会触发表级锁
- FLUSH TABLES WITH READ LOCK:可以给所有表加上全局读锁
3、不同的存储引擎主要用哪些锁?
- InnoDB存储引擎主要使用行级锁,并在一些情况下使用表级锁,如执行某些
ALTER TABLE
或LOCK TABLES
命令等 - MyISAM存储引擎只支持表级锁
4、表锁有哪些风险点?
- 性能下降:会锁整张表,可能会导致大量的请求阻塞
- 并发性能差:因为写锁会阻塞读写操作,读锁会阻塞写操作
- 可能导致锁等待和超时:由于表级锁粒度较大,可能会有很多线程在等待锁,如果等待时间过长,可能会导致锁超时
- 写操作影响大:如果一个长时间运行的写操作(如大数量量的UPDATE或INSERT)获取了写锁,那么会阻塞所有其他的读操作和写操作,直到这个写操作完成
- 死锁的可能性:如果获取顺序不对,可能会导致死锁(如线程A获取table1等待获取table2,线程B获取table2等待获取table1)
5、总结
为了避免上面提到的风险点,我们通常会选择InnoDB存储引擎,原因有:
- 它主要使用行级锁,可以提供更好的并发性能,并且在一定程度上减少了锁竞争的问题
- 而且,InnoDB还支持事务,可以保证数据的一致性和完整性
四、行锁
1、介绍
行级锁是MySQL的一种锁,可以对数据库表中的单一行进行锁定。相比表级锁和页锁,行级锁的粒度更小,因此在处理高并发事务时,能提供更好的并发性能和更少的锁冲突。
然而,行级锁也需要更多的内存和CPU资源,因为需要对每一行都进行管理
2、分类
InnoDB支持两种类型的行级锁:
- 共享锁(S锁):也称读锁,允许一个事务读取一行数据,允许其他事务读取该行数据,但不允许修改
- 排他锁(X锁):也称写锁,允许一个事务读取和修改一行数据,不允许其他事务读取和修改该行数据
3、什么时候生效?
- 行级锁只在事务中生效,也就是说,只有在一个事务开始(BEGIN)并在事务提交(COMMIT)或回滚(ROLLBACK)前,才会对数据行进行锁定
- 如果在非事务环节下执行SQL语句,那么InnoDB会在执行结束就释放所有的锁(如执行select xxx for update)
4、使用场景
- 高并发读写操作:在高并发读写场景下,行锁可以提高性能和并发性,因为它允许多个事务并发地操作不同的行
- 单行操作:对于需要操作单行数据的SQL语句(如基于主键或唯一索引的UPDATE、DELETE或INSERT语句),行级锁可以提供较好的并发性和性能
- 短期锁:在需要对某行数据进行短期锁定的情况下,行级锁可以防止长时间阻塞其他事务
- 实现并发控制
- 复杂的事务处理:在需要对多行数据进行复杂处理的事务中,行级锁可以锁定这些行,防止在事务处理过程中数据被其他事务修改
5、注意事项
- 由于行级锁的锁定粒度较小,它可能会消耗更多的系统资源(如内存和CPU),特别是在处理大量数据时
- 使用行级锁可能会导致死锁,需要使用合适的策略来避免死锁(如在事务中按照一定顺序锁定行)
6、MySQL哪些命令会发生行级锁
MySQL命令 | 添加锁类型 |
---|---|
SELECT … FOR UPDATE | 排他锁 |
SELECT … LOCK IN SHARE MODE | 共享锁 |
INSERT | 排它锁 |
UPDATE | 排它锁 |
DELETE | 排它锁 |
7、行锁有哪些风险点?
//TODO