MySQL事务隔离级别解决脏读 不可重复读 幻读问题

在上篇博客中我有提到过MySQL Inoodb引擎中的四大隔离级别,详细 点击打开链接

隔离级别分别为:

1.读未提交(read-uncommitted) 2.读已提交(read-committed) 3.可重复读(repeatable-read) 4.串行化(serializable);

下面我将对 ‘脏’读,不可重复读,幻读进行详细的介绍和各种隔离级别如何解决问题,以便于读者更深入了理解四个隔离级别的意义

 一、脏读

(一)问题:

打开客户端A,B设置隔离级别成 读未提交(read-uncommited),数据库默认级别是 可重复读(repeatable-read)。当前两个客户端的隔离级别设置成了 读未提交。如图1-1


图1-1


    第一步:客户端A更新数据 如图1-2

图1-2

     第二步:客户端B查看数据 如图1-3

     


图1-3

 第三步:客户端A回滚 当前数据库的记录 value=1,而客户端B读到的数据 value=2 如图1-4

图1-4

 (二)解决:MySQL应对策略-读已提交 (read-committed) 

     已经设置客户端A,B的隔离级别未读已提交

    第一步:客户端A更新 value=1->value=2 如图2-1

    


图2-1

    第二步:客户端B读取数据 如图2-2

图2-2

第三步:客户端A提交,此时客户端B再查询数据 数据才生效,因此 读已提交 解决了脏读的问题 如图2-3,2-4

图2-3


图2-4

二、不可重复读

    (一)问题:

       客户端A,B此时的隔离级别都是读已提交
       第一步:客户端A第一次读取数据 如图3-1


图3-1

        第二步:客户端B更新数据 value=2 如图3-2

图3-2

        第三步:客户端A第二次查询数据  第二次读取到的数据与第一次不一致,造成了不可重复读 

如图3-3


图3-3

(二)MySQL应对策略-可重复读

  客户端A,B设置隔离级别为可重复读

  第一步:客户端A读取数据 如图4-1

  

图4-1

   第二步:客户端B更新数据value=1 如图4-2

 图4-2

   第三步:客户端A第二次读取数据,value=2 值没有变换,所以避免了不可重复读的问题 如图4-3

如图4-3

三、幻读

(一)问题:

  当前客户端A,B的隔离级别是可重复读

  第一步:客户端A 查询数据  如图5-1,可知表中不存在id=2的数据

图5-1

第二步:客户端B在表中插入id=2的数据 如图5-2

图5-2

第三步:客户端A在表中插入id=2的数据,如图5-3,可见数据库报错,客户端A原本以为数据id=2的记录不存在,想要添加时候却发现 记录又存在了,就像‘幻影’一样,这就是幻读

如图5-3

(二)解决:MySQL应对策略-串行化(serialiable),主要加入了 next-key locks,具体的加锁过程可看:

   设置客户端A,B的隔离级别为串行化(serialiable)

   第一步:客户端A查询数据 如图6-1 不存在数据id=3的记录

图6-1

第二步:客户端B添加id=3的记录 如图6-2  出现了等待锁超时的情况 添加失败,只有等客户端A释放了锁之后,客户端B才能添加记录,因此解决了幻读的问题。

图6-2

以上言论,仅供学习使用,希望大家有不同看法的留言给我,谢谢大家。


在上篇博客中我有提到过MySQL Inoodb引擎中的四大隔离级别,详细 点击打开链接

隔离级别分别为:

1.读未提交(read-uncommitted) 2.读已提交(read-committed) 3.可重复读(repeatable-read) 4.串行化(serializable);

下面我将对 ‘脏’读,不可重复读,幻读进行详细的介绍和各种隔离级别如何解决问题,以便于读者更深入了理解四个隔离级别的意义

 一、脏读

(一)问题:

打开客户端A,B设置隔离级别成 读未提交(read-uncommited),数据库默认级别是 可重复读(repeatable-read)。当前两个客户端的隔离级别设置成了 读未提交。如图1-1


图1-1


    第一步:客户端A更新数据 如图1-2

图1-2

     第二步:客户端B查看数据 如图1-3

     


图1-3

 第三步:客户端A回滚 当前数据库的记录 value=1,而客户端B读到的数据 value=2 如图1-4

图1-4

 (二)解决:MySQL应对策略-读已提交 (read-committed) 

     已经设置客户端A,B的隔离级别未读已提交

    第一步:客户端A更新 value=1->value=2 如图2-1

    


图2-1

    第二步:客户端B读取数据 如图2-2

图2-2

第三步:客户端A提交,此时客户端B再查询数据 数据才生效,因此 读已提交 解决了脏读的问题 如图2-3,2-4

图2-3


图2-4

二、不可重复读

    (一)问题:

       客户端A,B此时的隔离级别都是读已提交
       第一步:客户端A第一次读取数据 如图3-1


图3-1

        第二步:客户端B更新数据 value=2 如图3-2

图3-2

        第三步:客户端A第二次查询数据  第二次读取到的数据与第一次不一致,造成了不可重复读 

如图3-3


图3-3

(二)MySQL应对策略-可重复读

  客户端A,B设置隔离级别为可重复读

  第一步:客户端A读取数据 如图4-1

  

图4-1

   第二步:客户端B更新数据value=1 如图4-2

 图4-2

   第三步:客户端A第二次读取数据,value=2 值没有变换,所以避免了不可重复读的问题 如图4-3

如图4-3

三、幻读

(一)问题:

  当前客户端A,B的隔离级别是可重复读

  第一步:客户端A 查询数据  如图5-1,可知表中不存在id=2的数据

图5-1

第二步:客户端B在表中插入id=2的数据 如图5-2

图5-2

第三步:客户端A在表中插入id=2的数据,如图5-3,可见数据库报错,客户端A原本以为数据id=2的记录不存在,想要添加时候却发现 记录又存在了,就像‘幻影’一样,这就是幻读

如图5-3

(二)解决:MySQL应对策略-串行化(serialiable),主要加入了 next-key locks,具体的加锁过程可看:

   设置客户端A,B的隔离级别为串行化(serialiable)

   第一步:客户端A查询数据 如图6-1 不存在数据id=3的记录

图6-1

第二步:客户端B添加id=3的记录 如图6-2  出现了等待锁超时的情况 添加失败,只有等客户端A释放了锁之后,客户端B才能添加记录,因此解决了幻读的问题。

图6-2

以上言论,仅供学习使用,希望大家有不同看法的留言给我,谢谢大家。


猜你喜欢

转载自blog.csdn.net/sunjinjuan/article/details/80916903