MySQL数据库的脏读、不可重复读、幻读问题
  TEZNKK3IfmPf 2023年11月14日 16 0

准备

先在数据库种执行select @@tx_isolation命令查看当前数据库的隔离级别。

MySQL数据库的脏读、不可重复读、幻读问题

MySQL数据库的默认隔离级别是REPEATABLE-READ,隔离级别就是数据库为了解决脏读、不可重复读和幻读问题的。

为了能够演示脏读、不可重复读和幻读,我们要先修改数据库的隔离级别,否则无法成功演示。

MySQL数据库的脏读、不可重复读、幻读问题

MySQL数据库有如上几种隔离级别,先将隔离级别修改为最低的READ UNCOMMITED,在这种隔离级别下,脏读、不可重复读和幻读的问题都会出现。

使用set tx_isolation='READ-UNCOMMITTED';命令修改隔离级别为最低的READ UNCOMMITED读未提交。

MySQL数据库的脏读、不可重复读、幻读问题

并且执行set autocommit=0取消事务的自动提交。

MySQL数据库的脏读、不可重复读、幻读问题

再准备这样一张表:

MySQL数据库的脏读、不可重复读、幻读问题

脏读

脏读的模拟过程:建立两个MySQL会话,分别为T1和T2,先在两个会话中查看account表的内容,都是一致的;接着在T2会话中执行一条UPDATE语句,对表中username为'lisi'的account字段进行了修改,但没有执行commit语句提交事务,这时候在T2会话中查看表的记录,是正确的,但在其他会话T1中查看表的记录已经是修改后的记录,如果这时候我们对这条username为'lisi'的记录进行操作,但恰巧T2会话回滚了刚才的操作,那么T1会话所做的事情都将会失效,因为这是错误的数据,这也就是脏读问题。

脏读:对于两个事务 T1, T2, T1 读取了已经被 T2 更新但还没有被提交的字段。之后, 若 T2 回滚, T1读取的内容就是临时且无效的。

MySQL数据库的脏读、不可重复读、幻读问题

那么如何解决脏读问题呢?MySQL数据库专门为解决这些问题提出了隔离级别,现在将隔离级别提升到READ COMMITED读取已提交,就能够解决脏读问题了。

执行set tx_isolation='READ-COMMITTED';命令修改隔离级别为READ COMMITED读已提交来解决脏读问题,在修改隔离级别后还需要执行commit;命令,因为刚才已经关闭了事务的自动提交,所以需要手动提交修改。注意:要回滚到'lisi'的account为1000,否则后面不方便查看。

MySQL数据库的脏读、不可重复读、幻读问题

再执行刚才的SQL操作,发现脏读问题已经被解决。

MySQL数据库的脏读、不可重复读、幻读问题

MySQL数据库的脏读、不可重复读、幻读问题

不可重复读

不可重复读模拟过程:在T1和T2会话中查看account表的数据是否为初始状态,然后在T1会话中查看username为'zhangsan'的字段的记录,接着在T2会话中对username为'zhangsan'的字段进行修改并且commit提交事务,再在T1会话中查看username为'zhangsan'的字段的记录,发现它们的account字段的值不一致,这就是发生了不可重复读问题,会造成不良的影响。

不可重复读:有两个事务T1和T2,T1先读取某个字段,然后T2对这个字段进行修改提交后,T1再读这个字段发现值不一样了。

MySQL数据库的脏读、不可重复读、幻读问题

如果要解决不可重复读问题,需要继续提升隔离级别。

执行set tx_isolation='REPEATABLE-READ';命令修改隔离级别为REPEATABLE READ可重复读来解决不可重复读问题,在修改隔离级别后还需要执行commit;命令,因为刚才已经关闭了事务的自动提交,所以需要手动提交修改。注意:要回滚到'lisi'的account为1000,否则后面不方便查看。

MySQL数据库的脏读、不可重复读、幻读问题

再执行刚才的SQL操作,发现脏读问题已经被解决。

MySQL数据库的脏读、不可重复读、幻读问题

只有当在T1会话中commit提交后才能看到已经在T2会话中更新的数据。

MySQL数据库的脏读、不可重复读、幻读问题

幻读

幻读过程模拟:先在1会话中查看记录条数,接着在T2会话中执行插入操作并进行commit提交,最后在T1会话中执行UPDATE操作,本来受影响的行数应该是2行,但实际上却是4行,这就是产生了幻读。

幻读:有两个事务T1和T2,T1先读取表,然后T2在该表中插入一些新行,此时T1再读同一个表,会发现多出来几行。

MySQL数据库的脏读、不可重复读、幻读问题

要解决幻读问题,需要将隔离级别调到SERIALIZABLE,执行set tx_isolation='SERIALIZABLE';命令修改隔离级别为SERIALIZABLE串行化来解决幻读问题,在修改隔离级别后还需要执行commit;命令,因为刚才已经关闭了事务的自动提交,所以需要手动提交修改。注意:要回滚到'lisi'的account为1000,否则后面不方便查看。

MySQL数据库的脏读、不可重复读、幻读问题

再执行刚才的SQL操作,发现脏读问题已经被解决。

MySQL数据库的脏读、不可重复读、幻读问题

只有当T1会话执行commit提交后才能进行操作:

MySQL数据库的脏读、不可重复读、幻读问题

总结

隔离级别就是为了解决脏读、不可重复读、幻读问题的。

隔离级别 是否解决脏读 是否解决不可重复读 是否解决幻读
READ UNCOMMITED × × ×
READ COMMITED × ×
REPEATABLE READ ×
SERIALIZABLE
【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月14日 0

暂无评论

推荐阅读
  TEZNKK3IfmPf   2024年05月31日   25   0   0 mysql
  TEZNKK3IfmPf   2024年05月31日   26   0   0 sqlite数据库
  TEZNKK3IfmPf   2024年05月31日   29   0   0 数据库mysql
  TEZNKK3IfmPf   2024年05月31日   27   0   0 数据库mysql
TEZNKK3IfmPf