本文意在弄清楚这些概念间的关系及其作用。弄清Mysql在开启事务的情况下,每条sql执行时的加锁操作和MVCC版本控制。为使讨论简单,本文忽略了GAP锁(间隙锁、范围锁)。
我们经常所高并发,高可用。就是从质和量来评估,任何事物都可以从这两个角度来分析。在Mysql数据库中,事务就是用来保证质的,MVCC就是用来保证量的。
我们使用事务来保证每一条SQL语句的结果执行符合我们的预期。我们说事务必须具备ACID特性。ACID中的三者:原子性、一致性和持久性其实描述的都差不多,保证SQL执行结果的可靠性。而隔离性就比较复杂了,隔离性描述的是在并发场景下数据库的表现,但并发量并不是固定的,而不同的业务可能有不同的需求,为了使数据库能适应不同的并发场景,所以伟大的人们又定义了四种隔离级别:Read Uncommited,Read Committed (RC),Repeatable Read (RR),Serializable。随着数据库隔离级别的提高,数据的并发能力也有所下降。
标准隔离级别下数据库会怎么表现可参考//www.Vevb.com/article/116477.htm,我们这里只讨论共享锁和排它锁这两概念,读加共享锁,写加排它锁:
在RC隔离级别下,修改数据会加排它锁,事务结束释放,其他事务不许读,解决脏读问题。(共享锁当场释放)
在RR隔离级别下,读数据加共享锁,事务结束释放,其他事务不许修改,解决不可重复读。(共享锁事务结束释放)
实际上都把操作串行化了。而Mysql对其进行了优化,一个事务读时其他事务不能写,一个事务写时其他事务不能读?我不这么干照样能解决脏读和不可重复读问题。MVCC出现了。(这也使得问题变得越来越复杂,而不一样的地方也开始出现在RR隔离级别下,碰巧Mysql的默认隔离级别就是RR)
MVCC即多版本并发控制,使用了双版本号来解决数据的隔离问题。(“create”一个版本号,“delete”一个版本号,修改操作拆分为“delete”和“create”)每个事务在开始对每张表增删改查操作时都会生成一个版本号,每个事务只能查到“create”小于本版本号和“delete”大于本版本号的数据。这样,增删查操作就完全可以并发进行了,只有修改操作是一定要排队的。这样,就算没有共享锁也解决了不可重复读问题,因为其他事务修改后,数据的版本号比我大,我不会读到。
引入MVCC之后,看似很美好。然而大家有没有想过两个事务先后对一条数据做更新操作,然后两个事务再读取那条数据,分别读到什么?哈哈,这根本是不可能出现的,因为修改操作是串行的,另一个事务必须先commit本事务才能修改。好,换个问题,两个事务先后对一条数据做+1操作,另一个事务提交后,本事务再+1,再读取那条数据,本事务是读取到+1还是+2的结果?如果读取到+2,那不是破坏了隔离性,读到了其他事务提交的数据么?
新闻热点
疑难解答