1.并发问题发生场景
并发问题产生的原因是多个线程操作了同一条记录,可分为三种场景。
1.1读-读
即并发事务相继读取相同的记录。
读操作不会改变数据本身,因此并不会引起并发问题。
1.2写-写
即并发事务相继对相同的记录做出改动。
这种情况下会发生脏写,是无论如何都要避免的。所以在多个事务相继对同一条记录进行写操作的时候,需要让他们排队执行,这个过程是通过在内存中创建一个排他锁来实现的。
关于这个锁的结构本文不做赘述,可以参考 MySQL 锁概述。
1.3读-写
也就是一个事务进行读取操作,另一个进行改动操作,这种情况下可能发生脏读、不可重复读、幻读的问题。
这些问题有两种解决方案:
-
方案一:MVCC + 锁
在读已提交隔离级别下,MVCC 机制解决了脏读问题。
在可重复读隔离级别下,MVCC 机制解决了脏读和不可重复读问题。
在可重复读隔离级别下,MVCC 机制 + 间隙锁(或临键锁)解决了幻读问题。
-
方案二:读写都加锁
如果我们的一些业务场景不允许读取记录的旧版本,而是每次都必须去读取记录的最新版本,比方在银行存 款的事务中,你需要先把账户的余额读出来,然后将其加上本次存款的数额,最后再写到数据库中。在将账 户余额读取出来后,就不想让别的事务再访问该余额,直到本次存款事务执行完成,其他事务才可以访问账 户的余额。这样在读取记录的时候也就需要对其进行加锁操作,这样也就意味着读操作和写操作也像写-写操 作那样排队执行。
很明显,一般情况下采用 MVCC + 锁 的方式系统的并发度更高。
参考:《MySQL 是怎样运行的》