首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >为什么在可重复读取中会发生写偏差?

为什么在可重复读取中会发生写偏差?
EN

Stack Overflow用户
提问于 2018-01-24 16:12:29
回答 1查看 4.1K关注 0票数 15

Wiki说;

可重复读取:

在此隔离级别中,基于锁的并发控制DBMS实现将保持读写锁(在选定数据上获取),直到事务结束。但是,范围锁不是托管的,因此可能会发生幻象读取。

在这种隔离级别上可能存在写偏差,这是一种现象,其中两个不同的写入器(他们之前已经读取了它们正在更新的列)允许对表中的同一列进行两次写入,从而导致该列具有两个事务的混合数据。

我很好奇为什么Repeatable reads中会发生write skew?它说它将保持读写锁,直到事务结束,当previously read the columns they are updating时发生write skew,那么当读锁被锁定时,如何锁定写锁呢?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-09-09 23:14:43

可重复读隔离级别保证每个事务将从数据库的consistent snapshot读取。换句话说,在同一事务中检索两次行总是具有相同的值。

许多数据库,比如可重复读隔离级别的Postgres、SQLServer都可以检测到lost update (写偏差的一种特殊情况),但其他数据库不能。(例如:MySQL中的InnoDB引擎)

我们又回来写倾斜现象的问题了。在可重复读隔离中,大多数数据库引擎无法检测到某些情况。一种情况是,当2并发事务修改2不同的对象并生成竞争条件时。

我举了Designing Data-Intensive Application一书中的一个例子。以下是场景:

你正在为医生编写一个应用程序来管理他们在医院的随叫随到的轮班。医院通常试图在任何时候都有几个医生随叫随到,但它绝对必须至少有一个医生随叫随到。医生可以放弃他们的轮班(例如,如果他们自己病了),前提是至少有一名同事在该轮班中随时待命

下一个有趣的问题是我们如何在数据库下实现这一点。下面是伪代码SQL代码:

代码语言:javascript
复制
BEGIN TRANSACTION;
    SELECT * FROM doctors
        WHERE on_call = true
        AND shift_id = 1234;
    if (current_on_call >= 2) {
        UPDATE doctors
        SET on_call = false WHERE name = 'Alice' AND shift_id = 1234;
    }
COMMIT;  

下面是插图:

如上图所示,我们看到Bob和Alice同时在SQL代码上运行。然而,Bob和Alice修改了不同的数据,Bob修改了Bob的记录,Alice修改了Alice的记录。处于可重复读取隔离级别的数据库无法知道并检查是否违反了条件(医生总>= 2)。写倾斜现象已经发生了。

为了解决这个问题,提出了两种方法:

  1. 锁定正在手动调用的所有记录。因此,鲍勃或艾丽斯将等待其他人完成transaction.

下面是一些使用SELECT .. FOR UPDATE查询的伪代码。

代码语言:javascript
复制
BEGIN TRANSACTION;
    SELECT * FROM doctors
        WHERE on_call = true
        AND shift_id = 1234 FOR UPDATE; // important here: locks all records that satisfied requirements.

    if (current_on_call >= 2) {
        UPDATE doctors
        SET on_call = false WHERE name = 'Alice' AND shift_id = 1234;
    }
  COMMIT;  

使用更严格的隔离级别的

  1. MySQLPostgres T-SQL都提供了序列化隔离级别。
票数 27
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/48417632

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档