Four isolation levels of database weak consistency

The original text is transferred from; http://www.cnblogs.com/xwdreamer/archive/2011/01/18/2297042.html

 

There are four isolation levels defined in the SQL-92 standard that were supported in previous versions of SQL Server :

READ UNCOMMITTED

READ UNCOMMITTED is the least restrictive isolation level because it ignores locks placed by other transactions. Transactions executed with the READ UNCOMMITTED level can read modified data values ​​that have not been committed by other transactions, behaviors called "dirty" reads. This is because at the Read Uncommitted level, reading data does not require an S lock, so it will not conflict with an X lock on the modified data . For example, transaction 1 modifies a row, and transaction 2 reads the row before transaction 1 commits. If transaction 1 rolls back, transaction 2 reads a row of uncommitted data, which we think does not exist.

READ COMMITTED

READ COMMITTED (Nonrepeatable reads) is the default isolation level of SQL Server . This level prohibits dirty reads by specifying that the statement cannot read data values ​​that have been modified by other transactions but have not yet been committed. Between executions of individual statements in the current transaction, other transactions can still modify, insert, or delete data, resulting in unrepeatable reads, or "shadow" data. For example, transaction 1 reads a row, transaction 2 modifies or deletes the row and commits. If transaction 1 wants to read the row again, it will get the modified data or find that this one has been deleted, so the second read result of the transaction is different from the first read result, so it is also called non-repeatable read .

Experiment 1

query1: transaction 1

copy code
--step1:创建实验数据
select * into Employee from AdventureWorks.HumanResources.Employee
alter table Employee add constraint pk_Employee_EmployeeID primary key(EmployeeID)

-- step2: Set the isolation level, which is the default isolation level of the database 
SET  TRANSACTION  ISOLATION  LEVEL  READ  COMMITTED

-- step3: Open the first transaction 
BEGIN  TRAN tran1
     -- step4: Execute the select operation, view VacationHours, add S lock to the searched records, and automatically release the S lock after the statement is executed 
    SELECT EmployeeID, VacationHours
         FROM Employee 
         WHERE EmployeeID =  4 ;

    -- step5: Check the current lock situation, and no lock is found on the Employee table, this is because the current isolation level is READ COMMITTED 
    -- The S lock is released immediately after step2 is executed. 
    SELECT request_session_id, resource_type, resource_associated_entity_id,
        request_status, request_mode, resource_description
        FROM sys.dm_tran_locks
copy code

Looking at the lock situation as shown in the figure below, we found that there are only S locks at the database level, but no locks at the table level or lower. This is because at the Read Committed level, the S lock is executed after the statement is executed. release .

query2: transaction 2

copy code
-- step6: Open the second transaction 
BEGIN  TRAN tran2;
     -- step7: Modify VacationHours, you need to obtain exclusive lock X, there is no S lock on VacationHours 
    UPDATE Employee 
         SET VacationHours = VacationHours -  8   
        WHERE EmployeeID =  4 ;

    -- step8: Check the current lock status 
    SELECT request_session_id, resource_type, resource_associated_entity_id,
        request_status, request_mode, resource_description
        FROM sys.dm_tran_locks
copy code

在开启另外一个update事务以后,我们再去查看当前的锁状况,如下图所示,我们发现在表(Object)级别上加了IX锁,在这张表所在的Page上也加了IX锁,因为表加了聚集索引,所以在叶子结点上加了X锁,这个锁的类型是KEY

然后我们回到事务1当中再次执行查询语句,我们会发现查询被阻塞,我们新建一个查询query3来查看这个时候的锁状况,其查询结果如下,我们可以发现查询操作需要在KEY级别上申请S锁,在Page和表(Object)上面申请IS锁,但是因为Key上面原先有了X锁,与当前读操作申请的S锁冲突,所以这一步处于WAIT状态。

如果此时提交事务2的update操作,那么事务1的select操作不再被阻塞,得到查询结果,但是我们发现此时得到的查询结果与第一次得到的查询结果不同,这也是为什么将read committed称为不可重复读,因为同一个事物内的两次相同的查询操作的结果可能不同

REPEATABLE READ

REPEATABLE READ是比READ COMMITTED限制性更强的隔离级别。该级别包括READ COMMITTED,并且另外指定了在当前事务提交之前,其他任何事务均不可以修改或删除当前事务已读取的数据。并发性低于 READ COMMITTED,因为已读数据的共享锁在整个事务期间持有,而不是在每个语句结束时释放。比如,事务1读取了一行,事务2想修改或者删除这一行并且提交,但是因为事务1尚未提交,数据行中有事务1的锁,事务2无法进行更新操作,因此事务2阻塞。如果这时候事务1想再一次读取这一行,它读取结果与第一次读取结果相同,因此叫可重复读。

实验2

query1:事务1

copy code
--step1:创建实验数据
select * into Employee from AdventureWorks.HumanResources.Employee
alter table Employee add constraint pk_Employee_EmployeeID primary key(EmployeeID)

--step2:设置隔离级别
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ

--step3:开启第一个事务
BEGIN TRAN tran1
    --step4:执行select操作,查看VacationHours
    SELECT EmployeeID, VacationHours
        FROM Employee 
        WHERE EmployeeID = 4;

    --step5:查看当前加锁情况,发现在Employee表上面有S锁,这是因为当前的隔离界别是REPEATABLE READ
    --S锁只有在事务执行完以后才会被释放.
    SELECT request_session_id, resource_type, resource_associated_entity_id,
        request_status, request_mode, resource_description
        FROM sys.dm_tran_locks
copy code

查询锁状态的结果如下图所示,我们发现在KEY上面加了S锁,在Page和Object上面加了IS锁,这是因为在Repeatable Read级别下S锁要在事务执行完以后才会被释放

 query2:事务2

copy code
--step6:开启第二个事务
BEGIN TRAN tran2;
    --step7:修改VacationHours,需要获得排他锁X,在VacationHours上有S锁,出现冲突,所以update操作被阻塞
    UPDATE Employee 
        SET VacationHours = VacationHours - 8  
        WHERE EmployeeID = 4;
copy code

执行上述update操作的时候发现该操作被阻塞,这是因为update操作要加排它锁X,而因为原先的查询操作的S锁没有释放,所以两者冲突。我们新建一个查询3执行查询锁状态操作,发现结果如下图所示,我们可以发现是WAIT发生在对KEY加X锁的操作上面。

此时再次执行查询1中的select操作,我们发现查询结果跟第一次相同,所以这个叫做可重复读操作。但是可重复读操作并不是特定指两次读取的数据一模一样,Repeatable Read存在的一个问题是幻读,就是第二次读取的数据返回的条目数比第一次返回的条目数更多。

比如在Repeatable Read隔离级别下,事务1第一次执行查询select id from users where id>1 and id <10,返回的结果是2,4,6,8。这个时候事务1没有提交,那么对2,4,6,8上面依然保持有S锁。此时事务2执行一次插入操作insert into user(id) valuse(3),插入成功。此时再次执行事务1中的查询,那么返回结果就是2,3,4,6,8。这里的3就是因为幻读而出现的。因此可以得出结论:REPEATABLE READ隔离级别保证了在相同的查询条件下,同一个事务中的两个查询,第二次读取的内容肯定包换第一次读到的内容。

SERIALIZABLE 

SERIALIZABLE 是限制性最强的隔离级别,因为该级别锁定整个范围的键,并一直持有锁,直到事务完成。该级别包括REPEATABLE READ,并增加了在事务完成之前,其他事务不能向事务已读取的范围插入新行的限制。比如,事务1读取了一系列满足搜索条件的行。事务2在执行SQL statement产生一行或者多行满足事务1搜索条件的行时会冲突,则事务2回滚。这时事务1再次读取了一系列满足相同搜索条件的行,第二次读取的结果和第一次读取的结果相同。

重复读与幻读

Repeated reading is to ensure that in a transaction, the data value read under the same query conditions does not change, but it cannot guarantee that the number of result records will not increase for the next query with the same conditions.

Phantom reading exists to solve this problem. He locks the query range, so you can no longer insert data into this range. This is what the SERIALIZABLE isolation level does.

The relationship between isolation level and lock

  1. Under the Read Uncommitted level, the read operation does not add S lock;
  2. At the Read Committed level, the read operation requires an S lock, but the S lock is released after the statement is executed;
  3. At the Repeatable Read level, the read operation needs to add the S lock, but the S lock is not released before the transaction is committed, that is, the S lock must be released after the transaction is completed.
  4. Under the Serialize level, a range lock will be added based on the Repeatable Read level. It is guaranteed that the results of two queries within a transaction are exactly the same, and there is no chance that the results of the first query are a subset of the results of the second query.

 

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=327058144&siteId=291194637