并发事务下出现的问题与解决
1.写-写情况:这种情况出现比较多的就是脏写,但是脏写是我们无法容忍的最严重的问题,因此多个未提交事务同时修改一条记录时,会采用加锁操作
过程如下:
- 一个事务想要对该记录进行写操作时,会看看内存中是否有与该记录关联的锁结构,如果没有,就会生成这样一个锁结构与之关联,锁结构信息比较多,我们挑两个最重要的讲,分别为,trx信息,即与哪个事务相关联,还有is_waiting,即表示该事务是否在等待
- 生成锁结构以后,因为之前没有其他锁占有该行,因此锁结构的is_waiting为false,这个场景就是获取锁成功或者说加锁成功
- 如果另外一个事务也需要对其进行改动,那就需要判断是否有锁与该记录关联,如果有,那么其也需要生成一个锁结构与之关联,但是由于该记录已经被其他事务的锁占有,因此其is_waiting为true,即表示在等待,该场景就是获取锁失败或者加锁失败
- 当上述第一个事务提交以后,就会把其生成的锁结构释放掉,取消与该记录的关联,此时还需要监测一下是否有其他锁结构与之关联,如果有则需要把其is_waiting置为false,并且唤醒,让第二个事务获取锁并且继续执行
(以上只是简单描述一下写-写获取锁与加锁的过程)
2.读-写或者写-读情况:这种情况下会出现脏读、不可重复读和幻读现象,因此就有四种事务隔离级别去解决,这几种级别如何避免这些问题呢?
- 方案一:读操作采用MVCC机制,写操作则加锁,快照读解决了不可重复读和幻读现象
- 方案二:读写操作均加锁,对于一些不能读取旧记录的场景
3.一致性读:涉及到MVCC读操作的都叫做一致性读,也叫快照读,其读取记录时,不会进行加锁操作
4.锁定读(读的时候设置的加锁方式):
- 共享锁和排他锁:
- 共享锁(Share Lock):简称S锁,事务读取一条记录时,会获取该记录的S锁
- 独占锁、排他锁(Exclusive Lock):简称X锁,当事务改动一条记录时,会获取该记录当X锁
S锁之间是相互兼容的,当事务一获取该记录当S锁时,事务二也可以获取S锁,即同时持有S锁,但是S锁与X锁,X锁与X锁是互不兼容的,当T1持有记录的S锁时,T2无法获取记录的X锁,X锁与X锁同理
- 锁定读的方式:
- 对读取的记录加S锁:SELECT …. LOCK IN SHARE MODE;
- 对读取对记录加X锁:SELECT …. FOR UPDATE;
5.几种改动操作获取锁的过程:
- DELETE:先找到删除的位置,然后获取该记录的X锁,再进行delete mark操作(只进行删除标记,不实际删除空间)
- UPDATE:
- 如果未修改记录的主键值,然后前后更新的列占用的存储空间未发生变化,即原来的存储空间可以容许这次改动时,先定位改动的位置,然后获取该记录的X锁,再在该原位置进行改动记录
- 如果未修改记录的主键值,但是更新记录时原来的存储空间不够大,不允许这次原位置改动,即改动前后存储空间会发生变化,因此先找到该位置,然后获取该记录的X锁,对该记录进行删除(该空间位置移入到垃圾链表),然后插入新的改动记录,再关联该X锁
- 如果修改了主键值,那么就需要先进行DELETE操作,在进行INSERT操作,按照这两个的规则来
- INSERT:插入记录会收到隐式锁保护,不需要在内存中为其生成锁结构
6.表级锁:上述的X锁和S锁都是针对单条记录的行级锁,对于整个全局表而言,也分为X锁和S锁,兼容性区分和行锁一致,但是一旦上锁,其针对的范围便是整张表.
但是在给表上X锁和S锁时,需要考虑其中是否已经有X和S行级锁,如果有那么就需要IS(意向共享锁)和IX(意向排他锁)这种方案来,如下:
