[MySQL]初识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
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的终值上面。
总结:
- 点赞
- 收藏
- 关注作者
评论(0)