准备
先在数据库种执行select @@tx_isolation命令查看当前数据库的隔离级别。
MySQL数据库的默认隔离级别是REPEATABLE-READ,隔离级别就是数据库为了解决脏读、不可重复读和幻读问题的。
为了能够演示脏读、不可重复读和幻读,我们要先修改数据库的隔离级别,否则无法成功演示。
MySQL数据库有如上几种隔离级别,先将隔离级别修改为最低的READ UNCOMMITED,在这种隔离级别下,脏读、不可重复读和幻读的问题都会出现。
使用set tx_isolation='READ-UNCOMMITTED';命令修改隔离级别为最低的READ UNCOMMITED读未提交。
并且执行set autocommit=0取消事务的自动提交。
再准备这样一张表:
脏读
脏读的模拟过程:建立两个MySQL会话,分别为T1和T2,先在两个会话中查看account表的内容,都是一致的;接着在T2会话中执行一条UPDATE语句,对表中username为'lisi'的account字段进行了修改,但没有执行commit语句提交事务,这时候在T2会话中查看表的记录,是正确的,但在其他会话T1中查看表的记录已经是修改后的记录,如果这时候我们对这条username为'lisi'的记录进行操作,但恰巧T2会话回滚了刚才的操作,那么T1会话所做的事情都将会失效,因为这是错误的数据,这也就是脏读问题。
脏读:对于两个事务 T1, T2, T1 读取了已经被 T2 更新但还没有被提交的字段。之后, 若 T2 回滚, T1读取的内容就是临时且无效的。
那么如何解决脏读问题呢?MySQL数据库专门为解决这些问题提出了隔离级别,现在将隔离级别提升到READ COMMITED读取已提交,就能够解决脏读问题了。
执行set tx_isolation='READ-COMMITTED';命令修改隔离级别为READ COMMITED读已提交来解决脏读问题,在修改隔离级别后还需要执行commit;命令,因为刚才已经关闭了事务的自动提交,所以需要手动提交修改。注意:要回滚到'lisi'的account为1000,否则后面不方便查看。
再执行刚才的SQL操作,发现脏读问题已经被解决。
不可重复读
不可重复读模拟过程:在T1和T2会话中查看account表的数据是否为初始状态,然后在T1会话中查看username为'zhangsan'的字段的记录,接着在T2会话中对username为'zhangsan'的字段进行修改并且commit提交事务,再在T1会话中查看username为'zhangsan'的字段的记录,发现它们的account字段的值不一致,这就是发生了不可重复读问题,会造成不良的影响。
不可重复读:有两个事务T1和T2,T1先读取某个字段,然后T2对这个字段进行修改提交后,T1再读这个字段发现值不一样了。
如果要解决不可重复读问题,需要继续提升隔离级别。
执行set tx_isolation='REPEATABLE-READ';命令修改隔离级别为REPEATABLE READ可重复读来解决不可重复读问题,在修改隔离级别后还需要执行commit;命令,因为刚才已经关闭了事务的自动提交,所以需要手动提交修改。注意:要回滚到'lisi'的account为1000,否则后面不方便查看。
再执行刚才的SQL操作,发现脏读问题已经被解决。
只有当在T1会话中commit提交后才能看到已经在T2会话中更新的数据。
幻读
幻读过程模拟:先在1会话中查看记录条数,接着在T2会话中执行插入操作并进行commit提交,最后在T1会话中执行UPDATE操作,本来受影响的行数应该是2行,但实际上却是4行,这就是产生了幻读。
幻读:有两个事务T1和T2,T1先读取表,然后T2在该表中插入一些新行,此时T1再读同一个表,会发现多出来几行。
要解决幻读问题,需要将隔离级别调到SERIALIZABLE,执行set tx_isolation='SERIALIZABLE';命令修改隔离级别为SERIALIZABLE串行化来解决幻读问题,在修改隔离级别后还需要执行commit;命令,因为刚才已经关闭了事务的自动提交,所以需要手动提交修改。注意:要回滚到'lisi'的account为1000,否则后面不方便查看。
再执行刚才的SQL操作,发现脏读问题已经被解决。
只有当T1会话执行commit提交后才能进行操作:
总结
隔离级别就是为了解决脏读、不可重复读、幻读问题的。
隔离级别 | 是否解决脏读 | 是否解决不可重复读 | 是否解决幻读 |
---|---|---|---|
READ UNCOMMITED | × | × | × |
READ COMMITED | √ | × | × |
REPEATABLE READ | √ | √ | × |
SERIALIZABLE | √ | √ | √ |