MySql事物隔离级别

 1. 未提交读

未提交读(read uncommitte)是最低的隔离级别,其含义是允许一个事物读取另外一个事物没有提交的数据。未提交读是一种危险的隔离级别,所以一般在我们实际的开发中应用不广,但是它的优点在于并发能力高,适合哪些对数据一致性没有要求而追求高并发的场景,它的最大坏处是出现脏读。让我们看看可能发生的脏读场景,如表6-3所示。

表6-3 脏读现象

时刻 事物1 事物2 备注
T0 ...... ...... 商品库存初始化为2
T1 读取库存为2    
T2 扣减库存   库存未1
T3   扣减库存 库存未0,读取事物1未提交的库存数量
T4   提交事物 库存保存未0
T5 回滚事物   因为第一类丢失更新已经克服,所以不会回滚未2,库存为0,结果错误

表6-3中的T3时刻,因为采用未提交读,所以事物2可以读取事物1未提交的库存数量为1,这里当它扣减库存后则数据未0,然后它提交了事物,库存就变未了0,未事物1在T5时刻回滚事物,因为第一类丢失更新已经被克服,所以它不会将库存回滚到2,那么最后的结果就变为了0,这样就出现了错误。

脏读一边是比较危险的隔离级别,在我们实际应用中采用得不多。为了克服脏读的问题,数据库隔离级别还提供了读写提交(read committed)的级别。

 2. 读写提交

读写提交(read committed)隔离级别,是指一个事物只能读取另外一个事物已经提交的数据,不能读取未提交的数据。例如,表6-3的场景在限制为读写提交后,就变为表6-4描述的场景了。

表6-4 克服脏读

时刻 事物1 事物2 备注
T0 ...... ...... 商品库存初始化为2
T1 读取库存为2    
T2 扣减库存   库存为1
T3   扣减库存 库存为1,读取不到事物1未提交的库存数据
T4   提交事物 库存保存为1
T5 回滚事物   因为第一类丢失更新已经克服,所以不会回滚未2,库存为1,结果正确

在T3时刻,由于采用了读写提交的隔离级别,因此事物2不能读取到事物1中未提交的库存1,所以扣减库存的结果依旧为1,然后它提交事物,则库存在T4时刻就变为了1。T5时刻,事物1回滚,因为第一类丢失更新已经克服,所以最后结果库存为1,这是一个正确的结果。但是读写提交也会产生下面的问题,如表6-5所描述的场景。

表6-5 不可重读场景

时刻 事物1 事物2 备注
T0 ...... ...... 商品库存初始化为1
T1 读取库存为1    
T2 扣减库存   事物未提价
T3   读取库存为1 认为可扣减
T4 提交事物   库存变为0
T5   扣减库存  失败,因为此时库存为0,无法扣减

在T3时刻事物2读取库存的时候,因为事物1未提交事物,所以读出的库存为1,于是事物2认为当前可扣减库存;在T4时刻,事物1已经提交事物,所以在T5时刻,它扣减库存的时候就发现库存为0,于是就无法扣减库存了。这里的问题在于事物2之前认为可以扣减,而到扣减那一步却发现已经不可以扣减,于是库存对于事物2而言是一个可变化的指,这样的现象我们称为不可重复读,这就是读写提交的一个不足。为了克服这个不足,数据库的隔离级别还提出了可重复读的隔离级别,它能够消除不可重读的问题。

3. 可重复读

可重复读的目标是克服读写提交中出现的不可重复读的现象,因为在读写提交的时候,可能出现一些值的变化,影响当前事物的执行,如上述的库存是个变化的值,这个时候数据库提出了可重复读的隔离级别。这样就能够克服不可重复读的现象如表6-6所示。

表6-6 克服不可重读

时刻 事物1 事物2 备注
T0 ...... ...... 商品库存初始化为1
T1 读取库存为1    
T2 扣减库存   事物未提价
T3   尝试读取库存 不允许读取,等待事物1提交
T4 提交事物   库存变为0
T5   读取库存  库存为0,无法扣除

可以看到,事物2在T3时刻尝试读取库存,但是此时这个库存已经被事物1实现读取,所以这个时候数据库就阻塞它的读取,直到事物1提交,事物2才能读取库存的值。此时已经是T5时刻,而读取到的值为0,这时就已经无法扣减了,显然在读写提交中出现的不可重复读的场景被消除了。但是这样也会引发新的问题的出现,这就是幻读。假设现在商品交易正在进行中,而后台有人也在进行查询分析和打印业务,让我们看看如表6-7所示可能发生的场景。

表6-7 幻读

时刻 事物1 事物2 备注
T0 读取库存50件   商品库存初始化为100,现在已经销售50笔
T1   查询交易记录,50笔   
T2 扣减库存   事物未提价
T3 插入1笔交易记录   不允许读取,等待事物1提交
T4 提交事物   库存49件,交易记录51笔
T5   读取库存  这里与查询的不一致,在事物2看来有一笔是虚幻的,与之前查询的不一致

这便是幻读现象,可重复读和幻读,是比较难理解的内容,这里分析一下。首先这里的笔数不是数据库存储的值,而是一个统计值,商品库存则是数据库存储的值,这一点是需要注意的。也就是幻读不是针对一条数据库记录而言,而是多条记录,例如,这51笔交易笔数就是多条数据库记录统计出来的。而可重复读针对数据库的单一记录,例如,商品的库存是以数据库里面的一条记录存储的,它可以产生可重复读,而不能产生幻读。

4. 串行化

串行化(Serializable)是数据库最高的隔离级别,它会要求所有的SQL都会按照顺序执行,这样就可以克服上述隔离级别出现的各种问题,所以它能够完全保证数据的一致性。

posted on 2021-03-07 20:24  bigstrong_code  阅读(92)  评论(0编辑  收藏  举报

导航