精华内容
下载资源
问答
  • Mysql-InnoDB 事务-一致性读(快照读)
    万次阅读 热门讨论
    2018-03-01 18:21:21

    数据库读,是数据库操作中很常见的一个操作,在数据库事务中也经常出现读取数据的操作,比如先读取是否存在,然后不存在就插入等,想要了解数据库事务,理解“读”这个操作必不可少。

    数据库读分为:一致非锁定读、锁定读。这里是mysql官方文档对于一致性读的讲解,翻译一下。

    首先,概括一下,我理解的这篇官方文档主要表达的意思:

    1. 一致非锁定读,也可以称为快照读,其实就是普通的读取即普通SELECT语句。
    2. 既然是快照读,故 SELECT 的时候,会生成一个快照。
    3. 生成快照的时机:事务中第一次调用SELECT语句的时候才会生成快照,在此之前事务中执行的update、insert、delete操作都不会生成快照。
    4. 不同事务隔离级别下,快照读的区别: READ COMMITTED 隔离级别下,每次读取都会重新生成一个快照,所以每次快照都是最新的,也因此事务中每次SELECT也可以看到其它已commit事务所作的更改;REPEATED READ 隔离级别下,快照会在事务中第一次SELECT语句执行时生成,只有在本事务中对数据进行更改才会更新快照,因此,只有第一次SELECT之前其它已提交事务所作的更改你可以看到,但是如果已执行了SELECT,那么其它事务commit数据,你SELECT是看不到的。

    下面是翻译正文(原文地址:https://dev.mysql.com/doc/refman/5.7/en/innodb-consistent-read.html)

     

    Consistent Nonlocking Reads 一致非锁定读(一致读、快照读)

    consistent read  means that  InnoDB  uses multi-versioning to present to a query a snapshot of the database at a point in time. The query sees the changes made by transactions that committed before that point of time, and no changes made by later or uncommitted transactions. The exception to this rule is that the query sees the changes made by earlier statements within the same transaction. This exception causes the following anomaly: If you update some rows in a table, a  SELECT  sees the latest version of the updated rows, but it might also see older versions of any rows. If other sessions simultaneously update the same table, the anomaly means that you might see the table in a state that never existed in the database.
    一致性读意味着InnoDB引擎使用多版本展示某个时间点的数据库的查询快照(一致性读是通过 MVCC(多版本并发控制) 为查询提供了一个基于时间的点的快照)。查询可以看到自己之前已提的所有事务所做的更改,看不到在查询开始之后的事务提交的更改(ps:可能会有疑问,READ COMMITTED隔离级别下是可以看到事务提交的更改的,这个疑问文档下面会有一句话解析,其实这是因为:READ COMMITTED 隔离级别下每一次查询都会提前更新数据库快照!)或者未提交的事务所做的更改。这个规则的例外情况是查询可以看到同一个事务中早期语句所作的更改。这个例外导致了一下异常现象:
    如果更新表中的一些行,SELECT 语句看到更新行的最新版本,但是也可能看到任何行的旧版本(ps:这后半句是什么意思?)
    如果有其它会话同时更新了同一张表,这个异常意味着你可能看到数据库中从未存在过的表的脏数据。
     

    If the transaction isolation level is REPEATABLE READ (the default level), all consistent reads within the same transaction read the snapshot established by the first such read in that transaction. You can get a fresher snapshot for your queries by committing the current transaction and after that issuing new queries.

    With READ COMMITTED isolation level, each consistent read within a transaction sets and reads its own fresh snapshot.

    Consistent read is the default mode in which InnoDB processes SELECT statements in READ COMMITTED and REPEATABLE READ isolation levels. A consistent read does not set any locks on the tables it accesses, and therefore other sessions are free to modify those tables at the same time a consistent read is being performed on the table.

    如果事务隔离级别是 REPEATABLE READ (默认级别),同一个事务中的所有一致性读都会读取此事务中第一次一致性读所生成的快照。你可以通过提交当前事务然后进行一个新的查询来得到一个最新的查询快照。
    使用 READ COMMITTED 隔离级别,事务中每次一致性读都会设置并读取当前最新的快照。

    在 READ COMMITTED 和 REPEATED READ 隔离级别下,一致性读是InnoDB 执行 SELECT 语句 的默认方式。一致性读不会对表的访问设置任何锁,因此其它的会话可以同时改变一张正在进行一致性读的表。

     

    Suppose that you are running in the default REPEATABLE READ isolation level. When you issue a consistent read (that is, an ordinary SELECT statement), InnoDB gives your transaction a timepoint according to which your query sees the database. If another transaction deletes a row and commits after your timepoint was assigned, you do not see the row as having been deleted. Inserts and updates are treated similarly.

     

    设想一下事务正在默认的 REPEATABLE READ 隔离级别下运行。当你进行一个一致性读(也就是说,一个普通的 SELECT 语句),InnoDB 会根据这次查询看到的数据库内容设置一个时间点。如果另外一个事务在这个时间点之后删除了其中一行并且提交,你不会看到这样被删除了。插入和更新也是被同样对待。
    (ps:就是说你先在事务1中select,然后事务2中进行delete、insert、update操作,然后再次再事务1中进行select 你是看不到delete、insert、update的结果的,因为第一次select已经形成了快照)
    Note

    The snapshot of the database state applies to SELECT statements within a transaction, not necessarily to DML statements. If you insert or modify some rows and then commit that transaction, a DELETE or UPDATE statement issued from another concurrent REPEATABLE READ transaction could affect those just-committed rows, even though the session could not query them. If a transaction does update or delete rows committed by a different transaction, those changes do become visible to the current transaction. For example, you might encounter a situation like the following:

    数据库状态的快照适用于事务中 SELECT 语句,对 DML(data manipulation language) 语句没有作用。如果你插入或者修改一些行然后提交事务,另一个 REPEATABLE READ 隔离级别的事务中之行一个 DELETE 或者 UPDATE 语句会影响到已提交的那些行,即使那个会话中不能查询到这些行。如果一个事务对另一个事务提交的行进行 更新或者删除 操作,那些改变在当前事务中是可以看到的。举个例子,你可能会遇到如下的情形:

    
    例子1:
    SELECT COUNT(c1) FROM t1 WHERE c1 = 'xyz';
    -- Returns 0: no rows match.
    DELETE FROM t1 WHERE c1 = 'xyz';
    -- Deletes several rows recently committed by other transaction.
    
    例子2:
    SELECT COUNT(c2) FROM t1 WHERE c2 = 'abc';
    -- Returns 0: no rows match.
    UPDATE t1 SET c2 = 'cba' WHERE c2 = 'abc';
    -- Affects 10 rows: another txn just committed 10 rows with 'abc' values.
    SELECT COUNT(c2) FROM t1 WHERE c2 = 'cba';
    -- Returns 10: this txn can now see the rows it just updated.

    ps:上面这个例子可能没看太明白,解释一下,其实有两个事务作对比就比较好理解了,不过文档上这里只贴出来了事务1,其它事务(比如事务2、事务3等)并没有贴出来作对比。上面第一个例子的意思就是说:查询xyz的时候没有查询到,但是delete的时候却删除了一些行,这是因为有其它事务修改了数据;第二个例子是说:查询abc的时候没有查询到,但是update的时候却更新到了,然后由于是本事务进行的更新,故而后续的查询都可以看到本事务所作的更改。总结下这两个例子想要表达的就是:REPEATED READ 隔离级别下,快照会在事务中第一次SELECT语句执行时生成,只有在本事务中对数据进行更改才会更新快照,因此,只有第一次SELECT之前其它已提交事务所作的更改你可以看到,但是如果已执行了SELECT,那么其它事务commit数据,你SELECT是看不到的。

    You can advance your timepoint by committing your transaction and then doing another SELECT or START TRANSACTION WITH CONSISTENT SNAPSHOT.

    可以通过提交事务将时间点提前,然后执行另一个 SELECT 或者 START TRANSACTION WITH CONSISTENT SNAPSHOT。

    This is called multi-versioned concurrency control.

    这被称为 多版本并发控制 (MVCC)。

     

    In the following example, session A sees the row inserted by B only when B has committed the insert and A has committed as well, so that the timepoint is advanced past the commit of B.

    接下来的例子,会话A可以看到B插入的数据,只有B已经提交了插入的数据并且A也已经提交了事务的时候,这是由于快照生成的时间点在B提交之前。

    
                 Session A              Session B
    
               SET autocommit=0;      SET autocommit=0;
    time
    |          SELECT * FROM t;
    |          empty set
    |                                 INSERT INTO t VALUES (1, 2);
    |
    v          SELECT * FROM t;
               empty set
                                      COMMIT;
    
               SELECT * FROM t;
               empty set
    
               COMMIT;
    
               SELECT * FROM t;
               ---------------------
               |    1    |    2    |
               ---------------------

    If you want to see the “freshest” state of the database, use either the READ COMMITTED isolation level or a locking read:

    如果想要看到数据库最新的状态,需要使用 READ COMMITTED 隔离级别或者锁定读:

    
    SELECT * FROM t FOR SHARE;

    With READ COMMITTED isolation level, each consistent read within a transaction sets and reads its own fresh snapshot. With LOCK IN SHARE MODE, a locking read occurs instead: A SELECT blocks until the transaction containing the freshest rows ends (see Section 14.5.2.4, “Locking Reads”).

    READ COMMITTED 隔离级别下,事务中每次一致性读都会设置并读取最新的快照。使用 LOCK IN SHARE MODE 模式,会进行锁定读:SELECT 会阻塞直到事务读取到最新的行 为止。

    Consistent read does not work over certain DDL statements:

    • Consistent read does not work over DROP TABLE, because MySQL cannot use a table that has been dropped and InnoDB destroys the table.

    • Consistent read does not work over ALTER TABLE, because that statement makes a temporary copy of the original table and deletes the original table when the temporary copy is built. When you reissue a consistent read within a transaction, rows in the new table are not visible because those rows did not exist when the transaction's snapshot was taken. In this case, the transaction returns an error: ER_TABLE_DEF_CHANGED, “Table definition has changed, please retry transaction”.

    一致性读对DDL(Data definition language)语句无效:
    • 一致性读对 DROP TABLE 无效,因为MySQL不能使用已经被删除的表,InnoDB会销毁表。
    • 一致性读对 ALTER TABLE 无效,这是因为这条语句会根据源表产生一个临时副本并且会删除源表当副本被创建时。当你在事务中再次进行一致读的时候,新表中的行对你是不可见的,因为当事务快照创建的时候这些行还不存在。因此,事务会返回错误: ER_TABLE_DEF_CHANGED, “Table definition has changed, please retry transaction”.

    --------以下不知道咋翻译了,也没看太明白啥意思,求高手伸出援手~
    The type of read varies for selects in clauses like INSERT INTO ... SELECT, UPDATE ... (SELECT), and CREATE TABLE ... SELECT that do not specify FOR UPDATE or LOCK IN SHARE MODE:
    读类型因字句中的select而异,如 INSERT INTO ... SELECT, UPDATE ... (SELECT), and CREATE TABLE ... SELECT ,并不特指 FOR UPDATE 或者 LOCK IN SHARE MODE:
    By default, InnoDB uses stronger locks and the SELECT part acts like READ COMMITTED, where each consistent read, even within the same transaction, sets and reads its own fresh snapshot.
    To use a consistent read in such cases, enable the innodb_locks_unsafe_for_binlog option and set the isolation level of the transaction to READ UNCOMMITTED, READ COMMITTED, or REPEATABLE READ (that is, anything other than SERIALIZABLE). In this case, no locks are set on rows read from the selected table.

    更多相关内容
  • MySQL InnoDB非锁定一致性读与锁定读 (一)MySQL InnoDB事务模型 (二)MySQL InnoDB锁模型 (三)MySQL InnoDB非锁定一致性读与锁定读 (四)MySQL InnoDB锁类型及幻象读问题 (五)MySQL InnoDB中各类语句...

    MySQL InnoDB非锁定一致性读与锁定读

    (一)MySQL InnoDB事务模型

    (二)MySQL InnoDB锁模型

    (三)MySQL InnoDB非锁定一致性读与锁定读

    (四)MySQL InnoDB锁类型及幻象读问题

    (五)MySQL InnoDB中各类语句加锁方式

    (六)事务的提交与回滚极死锁检测、处理和预防

    非锁定一致性读

    一致性读,意味着InnoDB使用“多本版”向查询提供数据库在某个时间点的快照,这样一来,查询能够看到该时间点之前事务提交的更新而不能看到之后事务提交或未提交的更新。但也存在例外情况。(稍后会做详细介绍)

    所谓一致性读,更具体的说,在REPEATABLE READ事务隔离级别下,同一事务内的一致性读均会读取到该事务中第一个读创建的快照,其他事务在之后提交或未提交的更新对当前事务的读均不可见,除非提交了该事务并开启新事务发起新查询。而在READ COMMIT隔离级别下,事务内的每个一致性读均会设置和读取自己新鲜的快照。其他事务在之后提交的更新对当前事务的读可见,未提交的更新对当前事务不可见。具体内容在介绍InnoDB四种隔离界别的时候已经做了相信介绍,具体可参考REPEATABLE READREAD COMMIT节的内容。

    一致性读是InnoDB引擎处理READ COMMITREPEATABLE READ隔离级别中SELECT的默认方式,不需要对SELECT访问的对象加锁,其他session中的事务可以在另一session中的事务读去的同时自由的修改相关对象,因此称为非锁定一致性读。

    本节开始时提到一致性读存在例外情况。下面以一个例子加以说明:


    可以看到,起初事务的隔离级别均为REPEATABLE-READSESSION 读取的内容为i=1,2,3的行,在SESSION B中的事务更新了i=3的行后SESSION A查询到的内容并没有改变,即时在SESSION B提交了该更新后SESSION A扔只能看到最开始的一致性读创建的快照。但是,在SESSION A中的事务执行UPDATE语句更新了被SESSION B更新的记录后(数据库快照只适用于SELECT语句,不适用与DML语句,所以事务中的DML语句是可以看到其他session中的事务的更新的,即时SELECT并不能看到这些)再次执行SELECT语句不仅可以看到快照中的数据,还可以看到更新后的数据。

    上述提到的一致性读由多版本并发控制(MVCC)原理实现(利用了InnoDBundo log)。需要注意的是,一致性读不适用于特定的DDL语句如DROP TABLEALTER TABLE。另外,对于 INSERT INTO ... SELECT, UPDATE ... (SELECT)CREATE TABLE ... SELECT 中未指定FOR UPDATELOCK IN SHARE MODESELECT默认情况下行为和READ COMMIT隔离级别下的普通SELECT一样,同一事务内设置和读取自己的新鲜快照。

    锁定读

    上一节介绍了一下InnoDB中的非锁定一致性读,与之对应的是锁定读。顾名思义,非锁定一致性读在某个事务读取记录时不加任何锁其他事务可以修改记录,而锁定读意味着某个事务读取记录时会加锁。锁定读分为两种类型:SELECT...FOR UPDATESELECT...LOCK IN SHARE MODE,前者会对读取的记录加X锁,阻塞其他事务的读请求和修改请求,直至事务提交释放锁资源;后者会对读取的记录加S锁,阻塞其他事务的修改请求但不会阻塞读取请求,直至事务提交释放锁资源。也正因为SELECT...FOR UPDATESELECT...LOCK IN SHARE MODE分别需要对查询的记录加X锁和S锁,因此分别会被其他正在读写和写的事务阻塞,直到这些事务结束。需要注意的是SELECT...FOR UPDATE仅适用于autocommit=0或者通过START TRANSACTION明确开启事务的情况。

    因为锁定读会阻塞其他事务的修改请求,因此可以有效解决上一节非锁定一致性读中提到的”异常“,也即,一个事物执行了普通SELECT后若其他的事务更新、插入了记录并提交,那么该事务内执行DML操作更新被其他事务更新或插入的记录后再次执行SELECT操作会看到更新后的结果。(具体可以查看上一节的示例)

    锁定读的一个典型应用场景

    假如要往子表插入一条记录,插入前首先要确认一下父表有无相关记录,只有在父表有对应记录时插入才能满足引用完整性约束。如果使用一致性读来查询父表来验证相关行存在,此时往子表插入时其他的session有可能更新或者删除刚才父表中查到的行,这样在子表中插入后就违反了引用完整性约束。为了避免该问题可使用锁定读SELECT...LOCK IN SHARE MODE,在事务中读取父表进行验证时,对相关记录加S锁,这样其他事务无法对相关记录进行DML操作,此时可在事务中安全的插入相关记录,待此操作完成并提交或回滚后其他事务才能对记录进行DML操作。

    还有一种情况,比如有两个session需要读取某表中的一行,在成功读取后在同一事物中更新该行,并在另外的表中插入刚开始读取到的行。若此时使用SELECT...LOCK IN SHARE MODE则会对读取到的记录加S锁,两个session在同时申请X锁进行更新时便发生死锁。另外,由于读取到了同一行内容,两个session在向同一表插入数据时会导致键重复的错误。这种情况下用SELECT...FOR UPDATE较合适,在读取的时候阻塞其他事物的读和更新请求。


    展开全文
  • MySQL目前流行的版本默认的事务隔离级别一般是可重复,一般我们理解在这个隔离级别下,我们新建两个事务A和事务B,事务A的修改是不影响事务B的,也就是说A事务修改数据后,B事务到的数据是不变的,也就是...

    说到数据库的隔离级别,我想大家都能说出一二,但是很多时候都是从网上看来的,很多都点到为止不够详细,并且没有经过实践的检验,所以有时候我们会发现有些东西并没有按照我们预期的来工作,这里就是一个例子。

    MySQL目前流行的版本默认的事务隔离级别一般是可重复读,一般我们理解在这个隔离级别下,我们新建两个事务A和事务B,事务A的修改是不影响事务B的,也就是说A事务修改数据后,B事务读到的数据是不变的,也就是可重复读,同时在next-key锁的作用下,又解决了幻读。不过这里有一个问题就是B事务读到的数据是什么时候的数据?这句话隐藏着一个操作,就是在事务A提交前,事务B已经进行过一次查询,否则,事务B会读取最新的数据,因为事务是在begin后第一次select等操作时才开启的。文字描述的可能不太好理解,所以,直接通过操作的截图来理解这一过程。

    首先是两个场景

    +------+------+------+------+
    | id   | name | addr | fk   |
    +------+------+------+------+
    |    2 | ss1  | 111  |    2 |
    |    5 | ss2  | 111  |    3 |
    |    6 | ss3  | 111  |    4 |
    |  999 | ss4  | 111  |    5 |
    | 1000 | ss5  | 111  |    6 |
    | 1008 | ssx  | 111  |  100 |
    | 1014 | xx   | 111  |    7 |
    | 1015 | xx   | 111  |    8 |
    | 1012 | xx   | 111  |  101 |
    | 1013 | xx   | 111  |  101 |
    |  888 | xxx  | 111  |    7 |
    |    1 | yy   | 111  |    9 |

    +------+------+------+------+

    图1中左边事务A,右边事务B,在此情况下,我们称事务B是可重复读的,因为两次读的结果是一样的,注意事务B读取的值是事务A修改后的值。

                                                                            图1

    那我们再来看一下图2,在已经执行begin的前提下,事务B读到的是事务A修改后的值。


                                                                              图2

    这是为什么呢?按照我们通常的理解,事务A的提交应该对事务B没有影响才对,怕不是我们对可重复有什么误解?

    先来看这样一个操作,查询当前事务的trx_id

    SELECT TRX_ID FROM INFORMATION_SCHEMA.INNODB_TRX  WHERE TRX_MYSQL_THREAD_ID = CONNECTION_ID();
    那么我们来尝试一下

    可以看到,在执行begin后并没有生成TRX_ID,也就是说此时事务还没有开始,根据此篇文章http://www.cnblogs.com/su-han/p/begin.html的说法,只有在执行了select或者以start transaction with consistent snapshot开始事务,才能够正式开启事务。这个过程涉及到了非锁定一致性读,也就是在事务第一次读取的时候生成了一个快照,在RR隔离级别下,该快照是事务开始时的数据,也即是产生了TRX_ID之后。更多关于非锁定一致性读和锁定一致性读可参考https://www.linuxidc.com/Linux/2017-08/146216.htm



    参考文献:[1] https://www.cnblogs.com/Mr-Dawei/p/7460909.html?utm_source=debugrun&utm_medium=referral

                   [2] http://www.cnblogs.com/su-han/p/begin.html

                   [3] https://blog.csdn.net/skiof007/article/details/53376751

                   [4] https://blog.csdn.net/zyz511919766/article/details/49451255

                   [5] https://www.linuxidc.com/Linux/2017-08/146216.htm

    展开全文
  • Oracle 数据库一致性读的原理

    千次阅读 2013-09-04 17:27:58
    Oracle 数据库一致性读的原理 在Oracle数据库中,undo主要有三大作用: 提供一致性读(Consistent Read)、回滚事务(Rollback Transaction)以及实例恢复(Instance Recovery)。所以,理解了这个三个方面的...

    Oracle 数据库一致性读的原理

    在Oracle数据库中,undo主要有三大作用: 提供一致性读(Consistent Read)、回滚事务(Rollback Transaction)以及实例恢复(Instance Recovery)。所以,理解了这个三个方面的机制也就理解了undo的工作原理。

    对一致性读的理解:

    一致性读的现象

    例如,表T上一行的name字段值原来为A。现在在会话1下,将之改为B(未提交),接着,还在会话1下,select该行的name字段的值,结果为B。而接下来,在会话2下,select该行的name字段的值,结果为A(这就是一致性读)。

    接着,在会话1下,输入commit,再在会话2下,select该行的name字段的值,结果为B(在执行select操作之前任何会话里的提交事务所做的修改,都可以查询出来)。

     

    一致性读的原理

     

    一、当用户A查询期间,用户B删除了表的最后一条记录,以此为例子来进行说明一致性读

    一致性读是相对于脏读(Dirty Read)而言的。假设某个表T中有10000条记录,获取所有记录需要15分钟时间,即当前时间为9点整,某用户A发出一条查询语句:select * from T,该语句在9点15分时执行完毕。当用户A(会话1)执行该SQL语句到9点10分的时候,另外一个用户B(会话2)发出了一条delete命令,将T表中的最后一条记录删 除并提交了。那么到9点15分时,A用户将返回多少条记录?

    如果返回9999条记录,则说明发生了脏读;如果仍然返回10000条记录, 则说明发生了一致性读。很明显,在 9点钟那个时间点发出查询语句时,表T中确实有10000条记录,只不过由于I/O的相对较慢,所以才会花15分钟完成所有记录的检索。对于Oracle 数据库来说,没有办法实现脏读,必须提供一致性读,并且该一致性读是在没有阻塞用户的DML的前提下实现的。

    那么undo数据是如何实现一致性读的呢?

    还是针对上面的例子。用户A在9点发出查询语句(select操作)时,服务器进程会将9 点那个时间点上的SCN号记录下来,假设该SCN号为SCN9.00。那么9点整的时刻的SCN9.00一定大于等于记录在所有数据块头部的ITL槽中的 SCN号[即事务槽的scn/fsc字段](如果有多个ITL槽,则为其中最大的那个SCN号)。

    注: ITL(Interested Transaction List)是Oracle数据块内部的一个组成部分,用来记录该块所有发生的事务,一个itl可以看作是一个记录,在一个时间,可以记录一个事务(包括提 交或者未提交事务)。当然,如果这个事务已经提交,那么这个itl的位置就可以被反复使用了,因为itl类似记录,所以,有的时候也叫itl槽位。

    当用户A执行select操作时,用户A对应的服务器进程会在扫描表T的数据块时,把扫描到的数据块头部的ITL槽(们)的SCN号[即事务槽的scn/fsc字段]与开始执行select操作时的SCN,即SCN9:00进行比较。不过在与当前扫描到的那一个事务槽进行比较之前,服务器进程会先判断该事务槽的flag字段是否为提交状态。

    若是未提交状态(顺便说下,该未提交的事务(最后一次)对数据行所做修改的时间无论早于或是晚于开始执行select操作的SCN,对一致性读是不影响的。因为select操作始终以提交的事务的提交SCN[即事务槽的scn/fsc字段]来与开始执行select操作时的SCN进行比较的,不会以事务(最后一次)对数据行所做修改的时间SCN来与之比较的),则(因为块延迟清除机制,这里的未提交不表示真的未提交,还得找事务表上的提交标记)还得根据事务槽上的XID字段找到段头块上的事务表里的对应行,看该行的cmt是否为提交,为提交,就是真的提交,为未提交,就是真的未提交。如果事务表里的对应行上cmt字段为未提交,则还得判断该未提交事务所在的事务槽的XID字段是否属于会话里记录过的事务XID【注释:会话(内存)上应该记录了会话期间修改了哪些表(记录“修改哪些表”这个信息,在回滚时,就可以知道回滚所在的会话修改了哪些表,不用去扫描数据库上的所有表,看表所在的数据块们的事务槽上有否属于自己的事务,从而确定该表是自己修改过的),还有在会话里输入rollback命令前的所有未提交事务的XID(即事务槽上的XID字段)信息(未提交事务的XID是一致性读和回滚都会用到的)。】,若是,就跳过该事务(因为该事务属于本会话的),若不是,则就通过该事务槽(即当前扫描到的那一个事务槽)上的uba字段找到该事务(槽)对应的undo块(确切地说,应该是该事务对应产生的undo chain尾部的那个undo记录)。这里要强调的一点是,在undo记录上,不仅记录了改变前的数据(原值),还记录了改变前的数据所在的数据块头部的ITL信息,即本undo记录对应的事务所在的事务槽上的上一个事务的信息。而在undo记录上的该上一个事务信息里的flag字段肯定是提交状态的,因为上一个事务若不是提交状态的话,其所在的事务槽是不能被下一个事务所覆盖的。这样,找到undo块后,服务器进程就可以把该undo记录里上一个事务信息的SCN号[即事务槽的scn/fsc字段]与开始执行select操作时的SCN,即SCN9:00进行比较,看哪个更大。如果该undo记录里上一个事务信息的SCN号比 SCN9.00要小,则可以将 该undo块中的被修改前的数据取出,再结合N号块里的数据行,从而构建出9点10分被更新之前的那个时间点的数据块内容,这样的数据块叫做CR块 (Consistent Read),服务器进程读取该CR块的内容即可;否则,如果该undo记录里上一个事务信息的SCN号比SCN9.00要大,则还是依旧通过该上一个事务信息里的uba字段找到该事务对应的undo块,该undo块里记录了同一个事务槽上上次事务的信息。以此类推。

    若是提交状态,则将数据块头部的ITL槽中当前扫描到的那一个事务槽的SCN号与SCN9:00之间进行比较,哪个更大。如果数据块头部的ITL槽中当前扫描到的那一个事务槽的SCN号比 SCN9.00要小,则说明该数据块在9点以后没有被更新,可以直接读取其中的数据;否则,如果数据块头部的ITL槽中当前扫描到的那一个事务槽的SCN号比SCN9.00要大,则说明该 数据块在9点以后被更新了,该块里的数据已经不是9点那个时间点的数据了,于是要通过当前扫描到的那一个事务槽的uba字段找到其对应的undo块,该undo块里记录了同一个事务槽上次事务的信息。以此类推。

    下面为了叙述简单些,就让例子中产生的事务完成操作后立即提交,这样,表T所在的数据块的事务槽都是提交状态(没有未提交状态)

    服务器进程在扫描表T的数据块时,会把扫描到的数据块头部的ITL槽中的SCN号与SCN9:00之间进行比较,哪个更大。如果数据块头部的SCN号比 SCN9.00要小,则说明该数据块在9点以后没有被更新,可以直接读取其中的数据;否则,如果数据块(只要有一个)ITL槽的SCN号比SCN9.00要大,则说明该 数据块在9点以后被更新了,该块里的数据已经不是9点那个时间点的数据了,于是要借助undo块。

    9点10分,B用户更新了表T的最后一 条记录并提交注意,在这里,提交或者不提交并不是关键,只要用户B更新了表T,用户A就会去读undo数据块)。假设被更新记录属于N号数据块。那么这 个时候N号数据块头部的(有一个)ITL槽的SCN号就被改为SCN9.10。当服务器进程扫描到被更新的数据块(也就是N号块)时,发现其(中有一个)ITL槽的SCN为 SCN9.10,大于发出查询(即select操作)时的SCN9.00,说明该数据块在9点以后被更新了。于是服务器进程到N号块的头部,找到SCN9.10所在的ITL槽。由 于ITL槽中的una字段记录了对应的undo块的地址,于是根据该地址找到undo块,将 undo块中的被修改前的数据取出,再结合N号块里的数据行,从而构建出9点10分被更新之前的那个时间点的数据块内容,这样的数据块叫做CR块 (Consistent Read)。对于delete来说,其undo信息就是insert,也就是说该构建出来的CR块中就插入了被删除的那条记录。随后,服务器进程扫描该 CR块,从而返回正确的10000条记录。

    二、事务(们)只在一个数据块上做修改,且该块只有一个事务槽,以此为例子来进行说明一致性读

    让我们继续把问题复杂化。
    假设在9点10分B用户删除了最后一条记录并提交以后,紧跟着9点 11分,C用户在同一个数据块里(也就是N号块)插入了2条记录。这个时候Oracle又是如何实现一致性读的呢(假设表T的initrans为1,也就是表T所在的数据块上只有一个ITL 槽)?因为我们已经知道,事务需要使用ITL槽,只要该事务提交或回滚,该ITL槽就能够被重用。换句话说,该ITL槽里记录的已经是SCN9.11,而不是SCN9.10了。这时,ITL槽被覆盖了Oracle的服务器进程又怎能找回最初的数据呢

    其中的秘密就在于,Oracle在undo记录中,不仅记录了改变前的数据,还记录了改变前的数据所在的数据块头部的ITL信息,即本undo记录对应的事务所在的事务槽上的上一个事务的信息
    因此,9点10分B用户删除记录(删除记录这个操作,称为事务1)时(位于N号块里, 并假设该N号块的ITL槽上的信息为[Undo_block0 / SCN8.50](这个是该ITL槽被SCN9.10时产生的事务覆盖前在ITL槽上的信息)),则Oracle会将改变前的数据(也就是insert)放到(事务1对应的)undo块(假设该undo块地址为Undo_block1)里,同时在 该undo块里记录删除前ITL槽上的信息(也就是[Undo_block0 / SCN8.50])。删除记录以后,该N号块的ITL槽上的信息变为 [Undo_block1 / SCN9.10];到了9点11分,C用户又在N号块里插入了两条记录(插入了两条记录这个操作,称为事务2),则Oracle将插入前的数据(也就是delete两条记录)放到(事务2对应的)undo块(假设该undo块的地址为Undo_block2)里,并将9点11分时的ITL槽的信息(也就是[Undo_block1 / SCN9.10])也记录到该undo块里。插入两条记录以后,该N号块的ITL槽上的信息改为 [Undo_block2 / SCN9.11]。

    那么当执行查询(select操作)的服务器进程扫描到N号块时,发现该N号块的ITL槽上的SCN(即scn/fsc字段)为SCN9.11,大于SCN9.00,于是到该ITL槽中uba字段指定的 Undo_block2处找到该undo块。发现该undo块里记录的ITL信息为[Undo_block1 / SCN9.10],其中的SCN9.10仍然大于SCN9.00,于是服务器进程继续根据ITL槽中记录的Undo_block1,找到该undo块。发现 该undo块里记录的ITL信息为[Undo_block0 / SCN8.50],这时ITL里的SCN8.50小于发出查询时的SCN9.00,说明这时undo块包含合适的undo信息,于是服务器进程不再找下 去,而是将N号块、Undo_block2以及Undo_block1的数据结合起来,构建CR块。将当前N号的数据复制到CR块里,然后在CR块里先回退9点11分的事务(即事务2),也就是在CR块里删除两条记录,然后再回退9点10分的事务(即事务1),也就是在CR块里插入被删除的记录,从而构建出9点钟时的数据(这里说明了如何构造CR块) Oracle就是这样,以层层嵌套的方式,查找整个undo块的链表,直到发现ITL槽里的SCN号小于等于发出查询时的那个SCN号为止

    注释:对ORA-1555错误的原因分析

    正常来说,当 前undo块里记录的SCN号(如下图中的undo_block1)要比上一个undo块里记录(如下图中的undo_block2)的SCN号要小。但是在查找的过程中,可能会发现当前undo块里记录的ITL 槽的SCN号比上一个undo块里记录的SCN号还要大。这种情况说明由于事务被提交或回滚,导致当前找到的undo块里的数据已经被其他事务覆盖了,于是我们无法再找出小于等于发出查询时的那个时间点的SCN号,这时Oracle就会抛出一个非常经典的错误——ORA-1555,也就是snapshot too old的错误

    以上的描述可以用图来描述:



    三、事务(们)只在一个数据块上做修改,且该块有多个事务槽,以此为例子来进行说明一致性读

            上一个例子中数据块的事务槽只有一个,现在分析数据块的事务槽有多个事务槽时,是如何构造出CR块的,从而达到select操作的一致性读的目的。以下图为例来进行分析:

    这里强调下,图中的三个事务槽都是在同一个数据块上的。
    红点表示一个事务。
    红点下的标识,如1/A,其中A表示该事务的名字,1表示该事务是在该数据块上第一个执行的事务。
    1,2,3.1,3.2,4,5表示各个事务执行的先后顺序(即按照时间顺序执行的),其中例如3.2中小数点后的2表示在同一SCN时有多个事务执行,而该事务(即事务D)是第2个执行的。
    注释:数据块(格式)上的seq(参数)表示在同一SCN时有多个事务执行(或说活动)
    这里每个事务所对应的SCN都是表示其提交的SCN。
    以事务槽1为例,它先后有三个事务在其上,分别是A,D,E。第一个占据事务槽1的是A,接着被事务D,D又被E覆盖。


    当用户A执行select操作时,用户A对应的服务器进程会开始扫描表T的数据块。假设当服务器进程扫描到该数据块头部的ITL槽(们)时,事务槽1此时已被事务E占据,事务槽2此时已被事务F占据。这样,服务器进程发现这两个事务槽的SCN号[即事务槽的scn/fsc字段]都比开始执行select操作时的SCN要大。所以,服务进程需要构造CR块,来保证select操作能一致性读。
    服务进程如何构造CR块?
    将当前扫描到的数据块的数据复制到CR块里。之后,它先比较事务槽1和2的SCN谁大,这里是事务槽2,则将事务F进行回滚,即将CR块还原到事务F前的状态。接着回滚事务E,D,  C,  B,这样CR块就完成了。
            随便再插上一句。这里是按时间顺序将各个事务槽上的各个事务进行回滚的,这样得到的CR块的内容才能和开始执行select操作时的原本数据块的内容一致。
    假如按事务槽号顺序将各个事务槽上的各个事务进行回滚的,则内容会不一致。
    例如,上图中的事务C、E、F都是对表T上的同一行的同一字段进行修改,事务C将该字段值改为1,事务E将该字段值改为2,事务F将该字段值改为3。
    那么,按照按时间顺序还原所得结果为1,而按事务槽号顺序(事务槽由小到大的顺序,在位于同一个事务槽上的事务仍然按照时间顺序)的结果为3.


    四、一个事务在多个数据块上做修改,且每个块都有多个事务槽,以此为例子来进行说明一致性读
    这多个块可以属于同一张表,也可以属于不同的表,对下面的结论都不影响。
    一个事务若修改了n个数据块,则该事务在每个数据块块头都会占据一个事务槽来填写该事务的信息。这样,该事务对应的undo chain 上就会记录了n个老事务(即每个块上该事务所占据的事务槽上一个的事务)的信息。

    那么,这n个老的事务怎么被服务器进程找到的呢?
    下面先以一个事务在一数据块上做修改,且每个块都有多个事务槽为例子。此时,该事务对应的(undo块上的)undo chain上就记录了一个老事务的信息。我们先看看undo chain上的各个undo记录与这个老事务相关的内容,这个内容存在于从undo chain尾端的undo记录(即dump出来的undo块的内容里的irb的值对应的undo记录,也即事务回滚时开始的那个undo记录)开始的每个undo记录里:
    KTB Redo
    op: 0x02  ver: 0x01 
    op: C  uba: 0x00c1adac.011f.0b 
    这里的uba指的是在undo chain 上本undo记录的前一个undo记录的地址。
    op:C ,C表示让服务器进程通过这里的uba去找前一个undo记录。(oracle怎么知道还要往上回朔找上级的撤消块条目呢,主要看如果撤消记录条目有op: C说明还要往上回朔)
    而在undo chain上的最后一个undo记录与这个老事务相关的内容如下:

    KTB Redo

    op: 0x04  ver: 0x01

    op: L itl: xid:  0x0003.00e.000002e4 uba: 0x00c00407.0122.08

                          flg: C---    lkc:  0     scn: 0x0000.003f86e4

    op:L,L表示让服务器进程不用再找下去了,因为已经找到老事务的信息,老事务的信息就是op:L后跟着的

    itl: xid:  0x0003.00e.000002e4 uba: 0x00c00407.0122.08  flg: C---    lkc:  0     scn: 0x0000.003f86e4

    (op:L后跟着的事务信息其实是本undo记录对应的事务所在的在的一个数据块的事务槽上的上一个的事务信息)

    当然,在undo chain上的最后一个undo记录与这个老事务相关的内容有可能是另一种情况,如下:

    KTB Redo
    op: 0x03  ver: 0x01
    op: Z
    
    op: Z,Z表示本undo记录对应的事务所在的事务槽已经没有可回溯的事务了。举个例子,事务槽1前后被三个事务所占据,分别是A,B,C,A先占据了事务槽1,
    接着B覆盖了A,C又覆盖了B。那么,由C可以回溯B,由B可以回溯A,但是A就不能再回溯上去了,因为A是事务槽1开始被使用后的第一个事务。这里所的本undo记录
    在该例子里指的就是A事务对应产生的undo记录。

     一个事务若修改了n个数据块,则该事务在每个数据块块头都会占据一个事务槽来填写该事务的信息。这样,该事务对应的undo chain 上就会记录了n个老事务(即每个块上该事务所占据的事务槽上一个的事务)的信息。

    比如,一个事务先修改了数据块1,再修改了数据块2,则在事务操作数据块1对应的undo记录上会出现如下内容(未试验过):

    KTB Redo

    op: 0x05  ver: 0x01

    op: R  itl: xid:  0x0003.00e.000002e4 uba: 0x00c00407.0122.08

                          flg: C---    lkc:  0     scn: 0x0000.003f86e4

    op:R后跟着的事务信息其实也是本undo记录对应的事务所在的在的一个数据块的事务槽上的上一个的事务信息。

    R与L的区别在于:R表示还要通过本undo记录的rci找到undo chain上的前一个undo记录,因为前一个undo记录(或再向前)有另一个老事务的信息,即R表示undo chain的剩余undo记录里存在另一个老事务信息。

    一个事务先修改了数据块1,再修改了数据块2,又修改了数据块1,会如何找到老事务?还没有试验过.



    二、回滚事务则是在执行DML以后,发出rollback命令撤销DML所作的变化。Oracle利用记录在ITL槽里记录的undo 块的地址找到该undo块,然后从中取出变化前的值,并放入数据块中,从而对事务所作的变化进行回滚。

    实例恢复则 是在SMON进程完成前滚并打开数据库以后发生。SMON进程会去查看undo segment头部(所谓头部就是undo segment里的第一个数据块)记录的事务表(每个事务在使用undo块时,首先要在该undo块所在的undo segment的头部记录一个条目,该条目里记录了该事务相关的信息,其中包括是否提交等),将其中既没有提交也没有回滚,而是在实例崩溃时被异常终止的 事务全部回滚。



    注释:

    pga中的一块区域用于存储用户的相关信息。


    展开全文
  • 一致性锁定一致性非锁定 产生的原因 在mysql数据库中,有一个行锁的概念。行锁有两种类型:共享锁(s),排它锁(x);x锁和s锁是不能互相兼容的,而s锁与s锁是可以互相兼容的;在mysql的设计中,在写操作的...
  • 而关于MVCC多版本一致性读,就是在同一个事务中,用户只能看到该事务之前已经生效的和该事务本身做的修改。 在innodb中“MVCC多版本一致性读”功能的实现是基于undo-log的。    图1 图1描述了...
  • 说说SQL Server 2005中的一致性读

    千次阅读 2013-09-02 20:18:28
    实验环境和代码 SQL Server 2000中的查询问题 查询的阻塞问题 ...SNAPSHOT与读一致性 数据库级别的行版本管理 总结 延伸阅读 实验环境和代码 本来实验的环境为 1 2
  • 一致性非锁定一致性锁定

    千次阅读 2019-03-02 18:49:03
    一致性的非锁定 在默认配置下innodb的隔离级别是repeatable read,innodb的select操作使用的是一致性非锁定 一致性的非锁定行(consistent nonlocking read,简称CNR)是指InnoDB存储引擎通过行多版本控制...
  • HDFS数据一致性

    千次阅读 2018-09-11 10:22:45
    2.NameNode如何保证元数据的一致性 3.校验和 4.为实现高可用,HDFS采用的诸多策略 4.1 冗余副本 4.2 机架感知 4.3 心跳机制 4.4 安全模式 4.5 校验和 4.6 回收站 4.7 元数据保护 4.8 快照机制 ...
  • UNDO三大作用与一致性读机制浅析

    千次阅读 2011-11-15 23:57:56
    1.一致性读(consistent read) 2.事务回滚(Rollback Transaction) 3.实例恢复(Instance Recovery) 一致性读 当会话发出一条SQL查询,将当前时间的SCN号记录下来,当进程扫描到表T的数据块,再与该块头部的ITL...
  • 最终一致性的理解

    万次阅读 2014-11-09 23:34:59
    一致性问题的历史发展  完美的一致性模型是:当做了一个更新操作,所有的观察者将看到这个更新。  在70年代后期的数据库系统,这个完美的一致性模型第一次被认为很难达到。  在90年代中期,随着更大规模的...
  • 有关一致性,实践中又可以分为:强一致性、单调一致性、最终一致性。 CAP中的C默认就是指:在分布式系统中的所有数据备份,在同一时刻是否同样的值。(等同于所有节点访问同一份最新的数据副本)。 1、强一致性...
  • 详细介绍MySQL数据库事务隔离级别的实现原理,以及MVCC一致性视图的概念和实现。
  • ZooKeeper能保证任何时刻到的数据绝对一致吗? Zookeeper的特点就是,分布式,高可用,...也就是说可用性和一致性是Zookeeper的关键特性,作为一个消息的中间商,做了一个可靠的信息传递和存储的角色。 但是了解下ZooKeep
  • Oracle数据库一致性读的原理

    千次阅读 2011-01-19 08:49:00
    Oracle数据库一致性读的原理
  • Oracle多版本和读一致性

    千次阅读 2012-06-13 16:21:36
    对于以Oracle后台的开发人员了解Oracle多版本和一致读尤其重要,因为它在很大程度上提升了数据库的并行操作。如果对并发了解的不够,通常会遇到以下几种情况: 1、破坏了数据的完整 2、随着用户数的增多,应用的...
  • 一致性、顺序一致性、弱一致性和共识

    万次阅读 多人点赞 2018-07-21 21:57:37
    1. 一致性(Consistency) 一致性(Consistency)是指多副本(Replications)问题中的数据一致性。可以分为强一致性、顺序一致性与弱一致性。 1.1 强一致性(Strict Consistency) 也称为: 原子一致性(Atomic ...
  • 分布式系统中的一致性模型

    千次阅读 2022-04-15 09:30:34
    一致性模型本质上是进程与数据存储的约定:如果进程遵循某些规则,那么进程对数据的读写操作都是可预期的。
  • 一致性非锁定(consistent nonlocking read)  一致性非锁定是值InnoDB存储引擎通过多版本控制(multi versioning)的方式来读取当前执行时间数据库中的数据。如果被的数据行被加了排他锁,在读取这行数据...
  • 一致性一致性 最终一致性

    千次阅读 2019-10-02 17:58:48
    在足球比赛里,一个球员在一场比赛中进三个球,称之...一致性(Consistency) 可用性(Availability) 分区容忍性(Partition tolerance) CAP原理指的是,这三个要素最多只能同时实现两点,不可能三者兼顾。因此在进行分...
  • 理解事务——原子性、一致性、隔离性和持久性

    万次阅读 多人点赞 2013-08-17 23:50:37
    事务更新一份数据,最终一致性保证在没有其他事务更新同样的值的话,最终所有的事务都会到之前事务更新的最新值。如果没有错误发生,不一致窗口的大小依赖于:通信延迟,系统负载等。  其他一致性变体还有:   ...
  • 针对Zk一致性,最近看了很多帖子,有的帖子说ZK弱一致性,有的帖子说ZK是强一致性,今天给大家做个正确的解释。 二、问题分析: 1、首先ZK集群的节点类型有三种,leader/follower/observer,其中oberser不参与...
  • 通俗易懂 强一致性、弱一致性、最终一致性、读写一致性、单调、因果一致性 的区别与联系什么是一致性一致性的种类导致一致性出现的原因强一致性 与 弱一致性一致性两个要求弱一致性一致性和弱一致性举例顺序...
  • 分布式数据库的数据一致性管理是其最重要的内核技术之一,也是保证分布式数据库满足数据库最基本的ACID特性中的 “一致性”(Consistency)的保障。在分布式技术发展下,数据一致性的解决方法和技术也在不断的演进,...
  • 一致性(Consistency) 是指多副本(Replications)问题中的数据一致性。可以分为强一致性、顺序一致性与弱一致性。 强一致性(Strict Consistency) 系统中的某个数据被成功更新后,后续任何对该数据的读取操作...
  • MySQL的MVCC和InnoDB的非一致性锁定

    千次阅读 2019-01-10 21:42:41
    在MySQL并发事务导致的死锁中提到InnoDB存储引擎默认事务隔离级别为 Repeatable Read,在这种情况下,select 查询记录时,不会存在...事务具有4个特性:原子性、一致性、隔离性和持久性。 事务的隔离性由锁实现,原...
  • 在足球比赛里,一个球员在一场比赛中进三个球,称之...一致性(Consistency) 可用性(Availability) 分区容忍性(Partition tolerance) CAP原理指的是,这三个要素最多只能同时实现两点,不可能三者兼顾。因此在进行...
  • Cache 一致性

    千次阅读 2019-06-16 16:13:16
    Write invalidate提供了实现Cache一致性的简单思想,处理器上会有一套完整的协议,来保证Cache一致性。比较经典的Cache一致性协议当属MESI协议,奔腾处理器有使用它,很多其他的处理器都是使用它的变种。 单核处理器...
  • Mysql默认隔离级别为什么是可重复

    千次阅读 多人点赞 2020-03-23 10:31:38
    知识点总结 1.数据库默认隔离级别: mysql —repeatable,oracle,sql server ...3.为什么mysql用的是repeatable而不是read committed:在 5.0之前只有statement一种格式,而主从复制存在了大量的不一致,故选用repeata...
  • 数据一致性解决方案

    千次阅读 2022-03-12 21:21:17
    数据一致性解决方案 CAP理论 C:一致性、A:可用性、P:分区容错性 CAP只能满足两个 CA:两阶段提交的严格选举协议 CP弱A:RAFT协议等多数派选举协议 AP:GOSSIP等冲突解决协议 数据一致性 时间一致性:所有相关数据...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 517,242
精华内容 206,896
关键字:

一致性读