`
hunter090730
  • 浏览: 191928 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

Repeatable Read Isolation Level(occur phantoms read and row movement)

 
阅读更多
Unlike a read committed scan, a repeatable read scan retains locks on every row it touches until the end of the transaction.  Even rows that do not qualify for the query result remain locked.  These locks ensure that the rows touched by the query cannot be updated or deleted by a concurrent session until the current transaction completes (whether it is committed or rolled back).  These locks do not protect rows that have not yet been scanned from updates or deletes and do not prevent the insertion of new rows amid the rows that are already locked.  The following graphic illustrates this point:



Note that the capability to insert new "phantom" rows between locked rows that have already been scanned is the principle difference between the repeatable read and serializable isolation levels.  A serializable scan acquires a key range lock which prevents the insertion of any new rows anywhere within the range (as well as the update or deletion of any existing rows within the range).

In the remainder of this post, I'll give a couple of examples of how we can get unexpected results even while running queries at repeatable read isolation level.  These examples are similar to the ones from my previous two posts.

Row Movement

First, let's see how we can move a row and cause a repeatable read scan to miss it.  As with all of the other example in this series of posts, we'll need two sessions.  Begin by creating this simple table:

create table t (a int primary key, b int)
insert t values (1, 1)
insert t values (2, 2)
insert t values (3, 3)

Next, in session 1 lock the second row:

begin tran
update t set b = 2 where a = 2

Now, in session 2 run a repeatable read scan of the table:

select * from t with (repeatableread)

This scan reads the first row then blocks waiting for session 1 to release the lock it holds on the second row.  While the scan is blocked, in session 1 let's move the third row to the beginning of the table before committing the transaction and releasing the exclusive lock blocking session 2:

update t set a = 0 where a = 3
commit tran

As we expect, session 2 completely misses the third row and returns just two rows:

a           b          
----------- -----------
1           1         
2           2          
Note that if we change the experiment so that session 1 tries to touch the first row in the table, it will cause a deadlock with session 2 which holds a lock on this row.

Phantom Rows

Let's also take a look at how phantom rows can cause unexpected results.  This experiment is similar to the nested loops join experiment from my previous post.  Begin by creating two tables:

create table t1 (a1 int primary key, b1 int)
insert t1 values (1, 9)
insert t1 values (2, 9)

create table t2 (a2 int primary key, b2 int)

Now, in session 1 lock the second row of table t1:

begin tran
update t1 set a1 = 2 where a1 = 2

Next, in session 2 run the following outer join at repeatable read isolation level:

set transaction isolation level repeatable read
select * from t1 left outer join t2 on b1 = a2

The query plan for this join uses a nested loops join:

  |--Nested Loops(Left Outer Join, WHERE:([t1].[b1]=[t2].[a2]))
       |--Clustered Index Scan(OBJECT:([t1].[PK__t1]))
       |--Clustered Index Scan(OBJECT:([t2].[PK__t2]))

This plan scans the first row from t1, tries to join it with t2, finds there are no matching rows, and outputs a null extended row.  It then blocks waiting for session 1 to release the lock on the second row of t1.  Finally, in session 1, insert a new row into t2 and release the lock:

insert t2 values (9, 0)
commit tran

Here is the output from the outer join:

a1          b1          a2          b2
----------- ----------- ----------- -----------
1           9           NULL        NULL
2           9           9           0
Notice that we have both a null extended and a joined row for the same join key!

Summary

As I pointed out at the conclusion of my previous post, I want to emphasize that the above results are not incorrect but rather are a side effect of running at a reduced isolation level.  SQL Server guarantees that the committed data is consistent at all times.

CLARIFICATION 8/26/2008: The above examples work as I originally described if they are executed in tempdb.  However, the SELECT statements in session 2 may not block as described if the examples are executed in other databases due to an optimization where SQL Server avoids acquiring read committed locks when it knows that no data has changed on a page.  If you encounter this problem, either run these examples in tempdb or change the UPDATE statements in session 1 so that they actually change the data in the updated row.  For instance, for the first example try "update t set b = 12 where a = 2".


====
Table t has an index on column a only.  The repeatable read scan of t in session 2 uses this index.

Updating column a of the third row from 3 to 0, moves the row from the end of the index to the beginning of the index.  Since the scan is already underway, it misses this row and returns only two rows.

Updating column b does not move the row since there is no index on this column.  Since the row does not move, the scan finds it and returns all three rows.
===
http://en.wikipedia.org/wiki/Isolation_(computer_science)#READ_COMMITTED

http://blogs.msdn.com/b/craigfr/

分享到:
评论

相关推荐

    MySQL数据库事务隔离级别介绍(Transaction Isolation Level)

    - 当前会话修改:登录MySQL客户端后,执行`SET TRANSACTION ISOLATION LEVEL <隔离级别>`,如`SET TRANSACTION ISOLATION LEVEL READ COMMITTED`。 锁机制是实现事务隔离的重要手段。MySQL中的锁分为共享锁(读锁)...

    浅析MYSQL REPEATABLE-READ隔离级别

    REPEATABLE-READ 即可重复读,set autocommit= 0或者START TRANSACTION状态下select表的内容不会改变。这种隔离级别可能导致读到的东西是已经修改过的。 比如: 回话一中读取一个字段一行a=1 在回话二里这个字段该行...

    微软内部资料-SQL性能优化3

    Prior to SQL Server 7.0, REPEATABLE READ and SERIALIZABLE isolation levels were synonymous. There was no way to prevent non-repeatable reads while not preventing phantoms. By default, SQL Server 2000 ...

    MySQL数据库:事务隔离级别.pptx

    SET [GLOBAL | SESSION] TRANSACTION ISOLATION LEVEL SERIALIZABLE | REPEATABLE READ | READ COMMITTED | READ UNCOMMITTED 说明:如果指定GLOBAL,那么定义的隔离级将适用于所有的SQL用户;如果指定SESSION,则...

    MySQL加锁处理分析@何登成1

    常见的 Isolation Level 有四种:Read Uncommitted、Read Committed、Repeatable Read、Serializable。 六、一条简单 SQL 的加锁实现分析 本节将对一条简单的 SQL 语句的加锁实现进行分析,包括 id 主键+RC、id ...

    mysql修改数据刷新页面直接显示

    mysql> set session transaction isolation level repeatable read; Query OK, 0 rows affected (0.00 sec) mysql> start transaction; Query OK, 0 rows affected (0.00 sec) -- session 2 mysql> set session ...

    深入理解Mysql事务隔离级别与锁机制.pdf

    在Mysql数据库中,默认的事务隔离级别是Repeatable Read,可以通过设置transaction isolation level的方式来改变事务隔离级别。锁机制在Mysql数据库中也可以通过加锁的方式来实现,例如select * from T where id=1 ...

    Hibernate 事物隔离级别 深入探究

    为了确保数据库的可靠性和一致性,Hibernate 提供了四种事务隔离级别,分别是 Serializable、Repeatable Read、Read Committed 和 Read Uncommitted。 一、Serializable 隔离级别 Serializable 隔离级别是最高级别...

    SQL SERVER中事务隔离级别的实例分析.pdf

    SET TRANSACTION ISOLATION LEVEL REPEATABLE READ; ``` 通过理解并适当地应用这些事务隔离级别,开发人员可以在保证数据一致性的同时,优化并发事务的执行,提高系统整体性能。在设计数据库应用时,深入理解这些...

    事务及其并发控制实验1

    常见的隔离级别包括Read Uncommitted、Read Committed、Repeatable Read、Serializable等。 7. 锁机制 锁机制是指数据库系统用于控制事务执行过程中的并发访问的机制。锁机制可以避免数据的不一致和丢失,提高...

    C#事务原理与实例

    在.NET框架中,通过设置TransactionScope对象的IsolationLevel属性,可以指定事务的隔离级别。改变隔离级别的效果是立即的,这意味着在事务执行过程中可以动态调整以适应不同的需求。 在实际应用中,开发者需要权衡...

    transaction_isolation:以与数据库无关的方式在ActiveRecord中设置事务隔离级别

    支持所有ANSI SQL隔离级别::serializable,:repeatable_read,:read_committed,:read_uncommitted。 另请参阅 gem,以获取有关死锁和序列化错误的自动重试事务。例子 ActiveRecord::Base.isolation_level( :...

    mysql insert锁机制1

    文中提到的是REPEATABLE READ级别,该级别可以防止脏读(Dirty Read)和不可重复读(Non-Repeatable Read),但在某些情况下可能会导致幻读。 4. Gap锁开启状态:默认情况下,InnoDB启用Gap锁(innodb_locks_unsafe...

    sql server优化事务处理

    5. **选择适当的隔离级别**:通过`SET TRANSACTION ISOLATION LEVEL`可改变事务隔离级别,但不同的隔离级别有不同的副作用,如Read Uncommitted可能导致脏读,Repeatable Read可能导致幻读,Serializable可能导致...

    事物体系,看不懂你打我

    其中,Read Uncommitted允许脏读,Read Committed可能导致不可重复读,Repeatable Read可能导致幻读,而Serializable是最高的隔离级别,避免了所有这些问题,但可能影响并发性能。MySQL默认的隔离级别是Repeatable ...

    Mysql事务1

    可以通过`SET SESSION TRANSACTION ISOLATION LEVEL`来更改隔离级别,例如设置为已提交读(READ COMMITTED)。 1.2.1. 未提交读(READ UNCOMMITTED) 在未提交读级别下,事务可以读取其他未提交的事务数据,可能...

    mysql原理之隔离级别1

    SQL 标准定义了四个隔离级别,它们分别是 Read Uncommitted、Read Committed、Repeatable Read 和 Serializable,每种级别都针对不同的并发问题提供了不同的解决方案。 Read Uncommitted(读取未提交内容)是最宽松...

Global site tag (gtag.js) - Google Analytics