首页 > 代码库 > 数据库 一致性读&&当前读

数据库 一致性读&&当前读

今天小伙伴问了一个sql的问题:

  update t set status=2 where id in(select id from t where status=1)

这个sql,在并发的情况下,会不会有问题?

 

假设:下面的讨论,数据库的事务隔离级别是read_committed

其实这个可以很容易测试一下,得出结论:存在丢失更新的问题。

 

先来理解两个概念:

 

1. 一致性读

  当前的数据库产品级别都实现了多版本一致性,即MVCC,那么有了MVCC,数据库实现了读写互不阻塞的效果。
但为了达到read_committed事务隔离级别,以及语句级的读一致性,select语句需要构建一个版本,数据库会根据一个版本号,来构建。
比如oracle使用scn号,为了构建这个版本,产生的读,称为一致性读。

 

2. 当前读
  数据库在写入的过程中,比如update,因为要验证constraint,冲突等,需要读到当前数据,包括没有commit的事务,这样就产生了当前读。

 

oracle中英文解释:

  一致性读:  Consistent read

  当前读:  Current read

 

而上面的这个语句,就存在了两种读取。

  select: 会进行一致性读,
  update:会进行当前读。

 

而在并发的情况下: 第二个update可能因为更新到同一行(其他更新本行的事务未提交),而被阻塞。
当另一个事务提交后,第二个update会再次构建当前读,会把status从2再次更新成2.

 

如何避免:

1. 更改语句:
    update t set status=2 where id in(select id from t where status=1) and status=1;

2. 调整事务的隔离级别