怎么解决脏读、不可重复读、幻读这些问题呢?其实有两种可选的解决方案
方案一、读操作利用MVCC(多版本并发控制),写操作进行加锁。
所谓的MVCC,就是生成一个ReadView,通过ReadView找到符合条件的记录版本(历史版本由undo log日志构成)。查询语句只能读到在生成ReadView之前已提交事所做的更改,在生成ReadView之前
未提交的事务或者之后才开启的事务所做的更改是看不到的。而写操作肯定针对的是最新版本的记录,读记录的历史本版和改动记录的最新版本本身并不冲突,也就是采用MVCC时,
读-写操作并不冲突。
普通的SELECT 语句在READ COMMITTED 和 REPEATABLE READ 隔离级别下会使用到MVCC读取记录。
-
在READ COMMITTED 隔离级别下,一个事务在执行过程中每次执行SELECT 操作时都会生成一个ReadView,ReadView的存在本身就保证了事务不可以读取到未提交的事务所做的更改,也就是避免了脏读现象
-
在REPEATABLE READ 隔离级别下,一个事务在执行过程中只有第一次执行SELECT操作才会生成一个ReadView,之后的SELECT操作都复用这个ReadView,这样也就避免了不可重复读和幻读的问题
方案二、读-写均加锁
小结对比发现:
-
采用MVCC方式的话,读-写 操作彼此并不冲突,性能高
-
采用加锁方式的话,读-写操作彼此需要排队执行,影响性能