文章背景
最近在复习Mysql的时候发现对于锁这方面的知识掌握的真是一言难尽,起因是在看到Innodb如何解决幻读的问题。
锁
根据锁的特性来分,可以把锁分为互斥锁和共享锁,根据锁的性能来分可以划分为乐观锁和悲观锁,根据锁的粒度分又可以分为表锁,行锁,间隙锁,next-key Lock,那么他们是怎样定义的,作用又都是什么,还有Innodb是怎样在RR级别下解决幻读问题的呢?
1.互斥锁与共享锁
独占锁是指该锁一次只能由一个线程持有,其它线程则无法获得,除非已持有锁的线程释放了该锁。一个线程只有在成功获取锁后才能继续往下执行,当离开竞争区域时则释放锁,释放的锁供其他即将进入数据竞争区域的线程获取。
常见的有:ReentrantLock。
从我们之前的互斥所就能看得出来,互斥锁是使用的一个状态来进行锁标记的,共享锁其实也差不多。
基本的流程是一样的,主要区别在于判断锁获取的条件上,由于是共享锁,也就允许多个线程同时获取,所以同步状态的数量同时的大于1的,如果同步状态为非0,则线程就可以获取锁,只有当同步状态为0时,才说明共享数量的锁已经被全部获取,其余线程只能等待。
最典型的就是ReentrantReadWriteLock里的读锁,它的读锁是可以被共享的,但是它的写锁确每次只能被独占。
乐观锁与悲观锁
悲观锁是基于一种悲观的态度类来防止一切数据冲突,它是以一种预防的姿态在修改数据之前把数据锁住,然后再对数据进行读写,在它释放锁之前任何人都不能对其数据进行操作,直到前面一个人把锁释放后下一个人数据加锁才可对数据进行加锁,然后才可以对数据进行操作,一般数据库本身锁的机制都是基于悲观锁的机制实现的;
特点:可以完全保证数据的独占性和正确性,因为每次请求都会先对数据进行加锁, 然后进行数据操作,最后再解锁,而加锁释放锁的过程会造成消耗,所以性能不高;
乐观锁是对于数据冲突保持一种乐观态度,操作数据时不会对操作的数据进行加锁(这使得多个任务可以并行的对数据进行操作),只有到数据提交的时候才通过一种机制来验证数据是否存在冲突(一般实现方式是通过加版本号然后进行版本号的对比方式实现);
特点:乐观锁是一种并发类型的锁,其本身不对数据进行加锁通而是通过业务实现锁的功能,不对数据进行加锁就意味着允许多个请求同时访问数据,同时也省掉了对数据加锁和解锁的过程,这种方式因为节省了悲观锁加锁的操作,所以可以一定程度的的提高操作的性能,不过在并发非常高的情况下,会导致大量的请求冲突,冲突导致大部分操作无功而返而浪费资源,所以在高并发的场景下,乐观锁的性能却反而不如悲观锁。
表锁,行锁,间隙锁,next-key Lock
行锁和表锁的区别:前者是对单行加锁 , 后者是对整表加锁, 区别是 是否涉及索引,如果涉及索引则为行级锁,否则就是表锁。
间隙锁:在行与行之间进行加锁操作。
next-key就是“行锁+间隙锁”,一起使用。