InnoDB中RR级别对于写数据的处理

快照读与当前读

可能有读者会疑惑,事务的隔离级别其实都是对于读数据的定义,但到了这里,就被拆成了读和写两个模块来讲解。这主要是因为MySQL中的读,和事务隔离级别中的读,是不一样的。

我们且看,在RR级别中,通过MVCC机制,虽然让数据变得可重复读,但我们读到的数据可能是历史数据,是不及时的数据,不是数据库当前的数据!这在一些对于数据的时效特别敏感的业务中,就很可能出问题。

对于这种读取历史数据的方式,我们叫它快照读 (snapshot read),而读取数据库当前版本数据的方式,叫当前读 (current read)。很显然,在MVCC中:

  • 快照读:就是select
    • select * from table ….;
  • 当前读:特殊的读操作,插入/更新/删除操作,属于当前读,处理的都是当前的数据,需要加锁。
    • select * from table where ? lock in share mode;
    • select * from table where ? for update;
    • insert;
    • update ;
    • delete;

事务的隔离级别实际上都是定义了当前读的级别,MySQL为了减少锁处理(包括等待其它锁)的时间,提升并发能力,引入了快照读的概念,使得select不用加锁。而update、insert这些“当前读”,就需要另外的模块来解决了。

当前读场景

表'user_money'结构

idint
uservarchar
moneyint

表'user_money'数据

idusermoney
1小明1000
2小李2000

update -- 当前读

事务A

begin;
select money from user_money where id=1; //(A)
select money from user_money where id=1; //(C)
update user_money set money = 3000 where money = 1000; //(D)
commit;

事务B

begin;
update user_money set money = 2000 where money = 1000; //(B)
commit;

2个事务按照ABCD的顺序执行。

则AC的读取结果为:

1000
1000

小明的最终money为2000.  D语句更新不成功,因为update读取的是当前最新版本的数据

for update -- 当前读 (lock in share mode 同理)

事务A

begin;
select money from user_money where id=1; //(A)
select money from user_money where id=1 for update; //(C)
update user_money set money = 3000 where money = 1000; //(D)
commit;

事务B

begin;
update user_money set money = 2000 where money = 1000; //(B)
commit;

2个事务按照ABCD的顺序执行。

则AC的读取结果为:

1000
2000

for update读取的money为2000.  因为for update读取的是当前最新版本的数据

参考:Innodb中的事务隔离级别和锁的关系

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值