sql四种事物隔离级别READUNCOMMITTED读未提交READECOMMITTED已提交读REPEATABLEREAD可重复读SERIALIZABLE可串行化事物并发执行是会遇到的一致性问题脏写 如果一个事物修改了另一个未提交事物修改过的数据,就是发生了脏写脏读 如果一个事物读取到了另一个事物修改的未提交的数据,就是发生了脏读不可重复读 如果一个事物多次读取一个数据之间另一个事物修改了该数据,读取的数据不一致,则说明不可重复读幻读 如果一个事物先根据一个条件查询一些数据,在该事物进行时,另一个事物写入了一些符合那个条件的记录,再次读取时查询到的数据量变了,就意味着发生了幻读现象各事物隔离级别下并发事物会发生的现象 事物隔离级别 脏读 不可重复读 幻读 READUNCOMMITTED 可能 可能 可能 READECOMMITTED 不可能 可能 可能 REPEATABLEREAD 不可能 不可能 可能 SERIALIZABLE 不可能 不可能 不可能MVCC多版本控制原理版本链 mysql再使用InnoDB存储引擎时,它的聚簇索引记录都会包含两个隐藏列:tryid:一个事物在对某条聚簇索引记录改动时,都会把事物id赋值给trxidrollpointer:每次对聚簇索引记录改动时,都会把旧版本写入到undo日志中。rollpointer就是该记录修改前的记录地址 通过最新记录可以找到旧的值,所有的版本值通过rollpointer连在一起形成了一个链表,链表头节点就是最新的记录。ReadeView 因为READECOMMITTED和REPEATABLEREAD的事物隔离级别下都要保证读到已提交的事物修改的记录。要怎么才能确定哪些数据才是当前事物应该读取的数据呢?InnoDB通过Readview来解决这个问题,Readview主要包含下面几个内容mids:生成Readview时当前系统中活跃的读写事物的事物id列表mintrxid:生成ReadView时,当前系统中读写事物id最小的,也就是mids中最小的maxtrxid:生成ReadView时,系统会分配给下一个事物的事物idcreatortrxid:生成该ReadView的事物id 有了ReadView就可以判断某条记录是否可以被当前事物可见,有如下判断逻辑当前数据的trxidcreatortrxid说明这条数据被当前事物修改的,所以是可以访问的。当前数据的trxidcreatortrxid说明该数据的事物是ReadView生成后才生成的,所以不可被访问当前数据的trxidcreatortrxid说名该数据在ReadView前就已经提交,所以是可以被访问的如果当前数据介于最大值和最小值之间,则需要判断是否在mids中,如果在,说明在生成ReadView时该数据的事物还是活跃的,说明不可被访问;如果不在,说明在生成ReadView时该数据的事物已经提交了,说明可以被访问。 如果某个版本的数据不可以被当前事物访问,这是就用到版本链了,通过该版本的rollpointer找到下一条记录,重复以上记录,直到找到可被当前事物访问的版本。MysqlReadView的生成时机 mysql的事物隔离级别READECOMMITTED与REPEATABLEREAD最大的区别就在于生成呢个ReadView的时机是不同的READECOMMITTED每次读取数据都会生成,所以其他事物提交数据,再次读取就能读到REPEATABLEREAD第一次读取数据时就生成,所以在第一次数据读取后,无论这期间其他事物怎么修改数据,再次读取都不会有影响。 mysql默认使用REPEATABLEREAD,多版本控制可以解决一部分幻读。原因是只能确保当前事物读取的数据是正确的,不能保证当前事物修改其他事物已提交的数据,如果修改了该记录再次读取就能读取到数据(通过加锁可以解决,不过性能有所所影响)。