锁的介绍 (7)
十、锁的定义及分类
1.锁的定义
锁是用来协调在多个线程并发访问同一共享资源时带来的安全问题。如果我们频繁的使用锁,在并发非常大的时候会带来性能问题。
频繁用锁必然会造成性能问题,但不用锁,又会造成安全问题,MySQL在安全问题和性能方面是如何做权衡的。MySQL并发性非常好,它是如何解决安全问题呢?——MVCC思想
2.锁的分类
1)从性能上划分:乐观锁和悲观锁
- 乐观锁(并发性能是比较好的):CAS自旋锁,是非常典型的乐观锁。乐观的认为,当前系统环境下的并发量并不是很大,当真的有并发发生的时候,才会去上锁。
- 悲观锁(并发性能要弱):悲观的认为当前系统环境下并发情况是非常严重的,所有的任务在执行时都要上锁。保证了安全性,牺牲了并发性。
2)从数据库操作的类型上划分:读锁和写锁
这两种锁都是属于悲观锁。
-
读锁(共享锁):对于读取同一行数据的并发来说,是可以同时进行的,但是写不行。
-
写锁(排他锁):在上了写锁之后及释放写锁之前,所有的其他并发操作(包括读和写),都不能进行。
3)从数据的操作粒度来上划分:表锁和行锁
- 表锁:对整张表进行上锁
- 行锁:对表中的某一行记录进行上锁
4.表锁
MyISAM默认是支持表锁的,也就是说在默认情况下,多个线程并发操作时,一个线程操作MyISAM表后,相当于是获取了该表的表锁,其他所有的操作都不能进行。
MyISAM不支持事务。
InnoDB如何上表锁:
- 手动上锁:
# 格式
lock table 表1 read/write,表2 read/write;
# 示例
lock table tb_book read;
读锁:当前会话能读能写,其他会话只能读不能写。
写锁:当前会话能读能写,其他会话不能读写。
- 查看当前会话获取的所有锁:
show open tables;
- 释放当前会话的所有锁,不会把其他会话持有的锁释放掉。
unlock tables;
5.行锁
InnoDB支持行锁,在并发事务里,每个事务的读写删的操作,相当于是上了行锁。也可以通过“for update”为select上行锁。行锁可以支持并发的读,所以行锁是一个读锁。
行锁的特点:上锁的开销大,加锁速度慢,但是细粒度更细,并发性更好。这也是InnoDB和MyISAM的区别。

上行锁的两种方式:
- update tb_author set name='m' where id = 1;
- select * from tb_author where id=1 for update;
6.事务的特性ACID
- 原子性:一个事务是一个最小(原子)的操作单位,一个事务中的多条sql语句要么同时成功,要么同时失败。
- 一致性:事务提交之前和回滚之后的数据是一致性的。
- 持久性:一旦事务被提交,对数据的影响是持久的。
- 隔离性:多个事务在并发操作下提供了一套隔离机制,通过设置不同的隔离级别会有不同的并发效果。
7.事务的隔离级别
- read uncommitted: 读未提交,一个事务中读到了另一个事务没有提交的数据,这种情况称为脏读。
- Read committed: 读已提交。一个事务中能读到另一个事务已经提交的数据,那么就出现了不可重复读,也就是说多次读到的数据有可能是不一致的。
- repeatable read(mysql默认的隔离级别): 可重复读,就是为了解决不可重复读的问题。会出现幻读(虚度)的情况:

在事务A中插入数据时,该条数据已被事务B插入了,那么在事务A中就不能进行插入,但事务A的查询依然是查不到该事务的。
怎么解决:通过上行锁,或者设置隔离级别为Serializable。

- Serializable:序列化 相当于是上了表锁,性能非常差,所以不要考虑。
8.MVCC思想
多版本并发控制 ( Multi-Version Concurrency Control )
MySQL在权衡安全性和并发性能上,通过使用MVCC思想,做了较好的控制,所以我们说MySQL的能力是我们互联网公司都认可的。

9.死锁
所谓的死锁就是在多个并发中,事务A和事务B都持有对方需要的锁,且双方都没办法释放手中的锁。

10.间隙锁
所谓的间隙锁,就是通过范围来上锁,对满足范围的区间实现上锁的效果


浙公网安备 33010602011771号