[MySQL]初识MySQL隔离级别

举报
dbin_mu 发表于 2020/02/26 20:25:09 2020/02/26
【摘要】 我们知道MySQL有四种不同的隔离级别,分别是:read-uncommit、read-commit、repeat-read和serializable。这四种隔离级别分别解决了不同的数据一致性问题,也存在不同的问题。

我们知道MySQL有四种不同的隔离级别,分别是:read-uncommit、read-commit、repeat-read和serializable。这四种隔离级别分别解决了不同的数据一致性问题,也存在不同的问题。可以通过MySQL的下列参数来设置不同的隔离级别:

transaction-isolation = {READ-UNCOMMITTED | READ-COMMITTED | REPEATABLE-READ | SERIALIZABLE}

read-uncommitted

该隔离级别下允许一个事务读取到其它事务未提交的写操作,比如下面事务trx 1在t2时刻读到了事务trx 2的修改结果,但是事务trx2并没有提交,我们称这种现象为脏读。脏读对事务没有任何意义,我们应该尽量的避免

a=1;
trx 1                  --------------------           trx 2
begin;                                                       begin;
(t1) select a; -> a==1
                                                                 update a=2;
(t2) select a; -> a==2
                                                                 rollback
commit;

read-committed

此隔离级别下解决了事务的脏读问题, 比如下面事务trx 2在t2时刻已经将a修改为2但没有提交,事务trx 1读到的仍然是a=1。在t3时刻事务trx2提交了修改,事务trx1读到了修改的结果a==2。

a=1;
trx 1                  --------------------           trx 2
begin;                                                       begin;
(t1) select a; -> a==1
                                                                 update a=2;
(t2) select a; -> a==1
                                                                 commit;
(t3) select a; -> a==2
commit;

虽然read-committed解决了脏读的问题,但是依然存在幻读的问题。如下所示,初始时a有两条记录(1,10),t2时刻事务2插入了一条a=5的记录但是没有提交,事务1读到的是(1,10)两条记录。在t3时刻事务2已经提交,此时事务1读到的是(1,5,10)3条记录。此问题被称为幻读,也称做不可重复读。

a=(1,10);
trx 1                  --------------------           trx 2
begin;                                                       begin;
(t1) select a>0; -> a==(1,10)
                                                                 insert a=5;
(t2) select a>0; -> a==(1,10)
                                                                 commit;
(t3) select a>0; -> a==(1,5,10)
commit;

repeated-read

该隔离级别下解决了脏读和幻读的问题,如下t2时刻事务2插入了一条a=5的记录但是没有提交,事务1读到的是(1,10)两条记录。在t3时刻事务2已经提交,此时事务1依然读到的是(1,10)2条记录

a=(1,10);
trx 1                  --------------------           trx 2
begin;                                                       begin;
(t1) select a>0; -> a==(1,10)
                                                                 insert a=5;
(t2) select a>0; -> a==(1,10)
                                                                 commit;
(t3) select a>0; -> a==(1,10)
commit;

该隔离级别存在的问题是lost update,该问题的发送场景如下:

a=1;
trx 1                  --------------------           trx 2
begin;                                                       begin;
(t1) @val1 = select a; -> @val1==1
(t2)                                                           @val2 = select a; -> @val2==1
                                                                set a=@val2+1;
(t3)                                                           commit;   -->  a=2
set a=@val1+2;
(t4) commit; --> a=3

t1,t2时刻事务trx1、trx2分别读到了a为1,t3时刻事务2将它修改成a+1=2并行提交,t4时刻事务1将它修改成a+2=3。最终a的值为3,为事务1的修改结果,事务2的修改结果就丢失了。这种情况称为lost update。

serializable

该隔离级别下很好的解决了lost udpate的问题,上面同样的两个事务执行过程如下:

a=1;
trx 1                  --------------------           trx 2
begin;                                                       begin;
(t1) @val1 = select a; -> @val1==1
(t2)                                                           @val2 = select a;  // block阻塞
set a=@val1+2;
(t3) commit; --> a=3
                                                                @val2==3
                                                                set a=@val2+1;
(t4)                                                          commit;   -->  a=4

如上所示,t2时刻事务2读取a的值是发生了阻塞等待,因为此时事务1正在读取a的值。直到t3时刻事务1提交完成,事务2才能读到a的值,结果为@val2==3,是事务1的修改结果。接下来事务2将它修改成a+1=4。事务1和事务2对a的修改都最终体现在了a的终值上面。

总结:

MySQL提供了四种不同的隔离级别,分别是:read-uncommit、read-commit、repeated-read和serializable,后三种隔离级别分别结果了脏读、幻读、lost update的问题。虽然serializable解决了全部的问题,但是实际运行时它的性能是最差的。所以日常生产环境中我们一般使用read-commit、repeated-read两种隔离级别,既能解决一些严重的不一致问题又能保持MySQL比较高的性能。


【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。