• 数据库读现象


    数据库读现象

    一. 数据库读现象

    数据库管理软件的 "读现象" 指的是当多个事务并发执行时,在读取数据方面可能碰到的问题,包括又脏读,不可重复读和幻读.

    ps: 对于一些数据库软件会自带相应的机制去解决脏读,不可重复读,幻读等问题, 因为这些自带的机制,下述的一些实验可能在某一数据库管理软件 的默认机制下并不成立,即我们并不能在所有数据库管理软件中看到所有的读现象。所以此处我们暂且抛开具体的某个数据库管理软件的默认机制的干扰,暂时假设没有附加任何机制为前提,单纯地去理解数据库的读现象。

    1.1、脏读 (dirty read)

    事务T2更新了一行记录的内容,但是并没有提交所做的修改。

    事务T1读取更新后的行,然后T1执行回滚操作,取消了刚才所做的修改。此时T1所读取的行就无效了,称之为脏数据。

    举例

    事务一 事务二
    步骤1 SELECT age FROM users WHERE id = 1; /* will read 20 */
    步骤2 UPDATE users SET age = 21 WHERE id = 1; /* No commit here */
    /* 步骤3 */ SELECT age FROM users WHERE id = 1; /* will read 21 */
    ROLLBACK; /* lock-based DIRTY READ */

    在这个例子中,事务2回滚后就没有id是1,age是21的数据了。那么事务1在步骤3的时候读取的是一个脏数据,即不准确的数据

    1.2、不可重复读取 (nonrepeatable read)

    事务T1读取一行记录,紧接着事务T2修改了T1刚才读取的那一行记录并且提交了。

    然后T1又再次读取这行记录,发现与刚才读取的结果不同。这就称为“不可重复”读,因为T1原来读取的那行记录已经发生了变化。

    举例

    在基于锁的并发控制中“不可重复读(non-repeatable read)”现象发生在当执行SELECT 操作时没有获得读锁(read locks)或者SELECT操作执行完后马上释放了读锁; 多版本并发控制中当没有要求一个提交冲突的事务回滚也会发生“不可重复读(non-repeatable read)”现象。

    事务一 事务二
    /* 步骤1 */ SELECT * FROM users WHERE id = 1;
    /* 步骤2 */ UPDATE users SET age = 21 WHERE id = 1; COMMIT; /* in multiversion concurrencycontrol, or lock-based READ COMMITTED */
    /* 步骤3 */ SELECT * FROM users WHERE id = 1; COMMIT; /*lock-based REPEATABLE READ */

    在这个例子中,事务2在步骤2中更新可id=1的数据并提交成功,因此他对id为1的行的修改就对其他事务可见了。但是事务1在此前已经从这行读到了另外一个“age”的值。俩次相同的sql语句返回数据确实不一样的,即为不可重复读.

    1.3、幻像读取 (phantom read)

    幻读(phantom read)”是不可重复读(Non-repeatable reads)的一种特殊场景:
    当事务没有获取范围锁的情况下执行SELECT … WHERE操作有可能会发生“幻影读(phantom read)”。

    事务T1读取或修改了指定的WHERE子句所返回的结果集。

    然后事务T2新插入一行记录,这行记录恰好可以满足T1所使用的查询条件中的WHERE 子句的条件。

    然后T1又使用相同的查询再次对表进行检索,但是此时却看到了事务T2刚才插入的新行或者发现了处于WHRE子句范围内,但却未曾修改过的记录。就好像“幻觉”一样,因为对T1来说这一行就像突然出现的一样。

    一般解决幻读的方法是增加范围锁RangeS,锁定检锁范围为只读,这样就避免了幻读。

    举例

    当事务1两次执行SELECT … WHERE检索一定范围内数据的操作中间,事务2在这个表中创建了(如INSERT)了一行新数据,这条新数据正好满足事务1的“WHERE”子句。

    事务一 事务二
    /* 步骤1 */ SELECT * FROM usersWHERE age BETWEEN 10 AND 30;
    /* 步骤2 */ INSERT INTO users VALUES ( 3, 'Bob', 27 ); COMMIT;
    /* 步骤 3 */ SELECT * FROM usersWHERE age BETWEEN 10 AND 30;

    在这个例子中,事务一执行了两次相同的查询操作。但是两次操作中间事务二向数据库中增加了一条符合事务一的查询条件的数据,导致幻读。

    总结:

    -- 脏读就是多个事务并发执行时,事务1多次查看的数据的中间,别的事务修改了它查询的数据,但是未提交,导致事务1查看的数据不准确,这时候别的事务回滚了,就导致事务1查看了一条脏数据
    
    -- 不可重复读是多个事务并发执行时,事务1第一次查看的是数据是一种状态,期间别的事务对这个数据进行了修改,并提交了.那么就导致了事务1第二次查看的数据和第一次查看的数据状态不一样.相同的sql语句产生了俩种状态.
    
    -- 幻读,就是不可重复读的一种特殊状态,事务1第一次查看的表的数据是一种状态,期间别的事务往这个表中插入了一条新数据,并且提交了.那么事务1再次查询发现和第一次的id和别的数据对不上了.以为幻读了.
    

    二 解决方案

    其实,脏写、脏读、不可重复读、幻读,都是因为业务系统会多线程并发执行,每个线程可能都会开启一个事务,每个事务都会执行增删改查操作。然后数据库会并发执行多个事务,多个事务可能会并发地对缓存页里的同一批数据进行增删改查操作,于是这个并发增删改查同一批数据的问题,可能就会导致我们说的脏写、脏读、不可重复读、幻读这些问题。

    所以这些问题的本质,都是数据库的多事务并发问题,那么为了解决多事务并发带来的脏读、不可重复读、幻读等读等问题,数据库才设计了锁机制事务隔离机制、MVCC 多版本隔离机制,用一整套机制来解决多事务并发问题,下面我们来分别介绍一下它们

  • 相关阅读:
    著名的小退问题
    Oracle学习笔记(十二)
    Oracle学习笔记(十一)
    Oracle学习笔记(十)
    Oracle学习笔记(九)
    Oracle学习笔记(八)
    Oracle学习笔记(七)
    Oracle学习笔记(六)
    Oracle学习笔记(五)
    Oracle学习笔记(四)
  • 原文地址:https://www.cnblogs.com/jkeykey/p/14457507.html
Copyright © 2020-2023  润新知