6.基于快照的隔离级别,SQL Server将提交过的行保存到tempdb数据库中,当读操作发现行的当前版本和它们预期的不一致时,可以立即得到行的以前版本,从而不用请求共享锁也能取得预期的一致性。
4.隔离级别的行为方式★ 1.未提交读 (READ UNCOMMITTED)
打开两个查询窗口,Connetion1,connection2
Step1: 执行Connection1的阶段2的SQL 语句,然后执行connection2的SQL语句
Step2: 执行Connection1的阶段3的SQL 语句,执行connection2的SQL语句
Step3: 执行Connection1的阶段4的SQL 语句,执行connection2的SQL语句
查询窗口 事务 执行语句
Connetion1 A
--阶段2 UPDATE myProduct SET price = price + 1 WHERE id = 1; SELECT id , price FROM dbo.myProduct WHERE id = 1; --阶段3 UPDATE myProduct SET price = price + 5 WHERE id = 1; SELECT id , price FROM dbo.myProduct WHERE id = 1; --阶段4 COMMIT TRAN
Connection2 B
--在阶段2执行之后 SET TRAN ISOLATION LEVEL READ UNCOMMITTED BEGIN TRAN; SELECT id , price FROM dbo.myProduct WHERE id = 1 COMMIT TRAN;
两个事务的流程图:
阶段1:Price=10,事务A对myProduct表请求排他锁
阶段2:事务A对myProduct表使用了排他锁,更新price = price + 1,然后事务A查询price的价格: price=11。事务B不请求任何锁,事务B在A更新Price之后进行查询,price=11
阶段3:事务A更新price = price + 5,然后事务A查询price的价格,price = 16。事务B查询price的价格: price=16
阶段4:事务A释放排他锁
阶段5:事务A中查询price的价格:price = 16。事务B查询price的价格: price=16
大家可以看到事务B有两种结果,这就是“未提交读 (READ UNCOMMITTED)”隔离级别的含义:
(1)读操作可以读取未提交的修改(也称为脏读)。
(2)读操作不会妨碍写操作请求排他锁,其他事务正在进行读操作时,写操作可以同时对这些数据进行修改。
(3)事务A进行了多次修改,事务B在不同阶段进行查询时可能会有不同的结果。
★ 2.已提交读(READ COMMITTED)(默认值)
打开两个查询窗口,Connetion1,connection2
Step1: 执行Connection1的SQL 语句
Step2: 执行Connection2的SQL 语句
执行语句 执行语句
Connetion1 A
UPDATE dbo.myProduct SET price = price + 1 WHERE id=1 SELECT * FROM dbo.myProduct WHERE id =1
Connection2 B
SET TRANSACTION ISOLATION LEVEL READ COMMITTED SELECT * FROM dbo.myProduct WHERE id = 1
两个事务的流程图:
阶段1:Price=10,事务A对myProduct表请求排他锁
阶段2:事务A对myProduct表使用了排他锁,更新price = price + 1,然后事务A查询price的价格: price=11。然后事务B请求共享锁进行读操作,查询price,
由于在当前隔离级别下,事务A的排他锁和事务B的共享锁存在冲突,所以事务B需要等待事务A释放排他锁后才能读取数据。
阶段3:事务A提交事务(COMMIT TRAN)
阶段4:事务A提交完事务后,释放排他锁
阶段5:事务B获得了共享锁,进行读操作,price=11
“已提交读 (READ UNCOMMITTED)”隔离级别的含义:
(1)必须获得共享锁才能进行读操作,其他事务如果对该资源持有排他锁,则共享锁必须等待排他锁释放。
(2)读操作不能读取未提交的修改,读操作读取到的数据是提交过的修改。
(3)读操作不会在事务持续期间内保留共享锁,其他事务可以在两个都操作之间更改数据资源,读操作因而可能每次得到不同的取值。这种现象称为“不可重复读”
★ 3.可重复读(REPEATABLE READ)
打开两个查询窗口,Connetion1,connection2
Step1: 执行Connection1的SQL 语句
Step2: 执行Connection2的SQL 语句
执行语句 事务 执行语句
Connetion1 A
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ SELECT * FROM dbo.myProduct WHERE id = 1
Connection2 B
UPDATE dbo.myProduct SET price = price + 1 WHERE id=1
两个事务的流程图:
阶段1:Price=10,事务A对myProduct表请求共享锁
阶段2:事务A对myProduct表使用了共享锁,事务A查询price的价格: price=10,事务A一直持有共享锁直到事务A完成为止。然后事务B请求排他锁进行写操作price=price+1,
由于在当前隔离级别下,事务A的共享锁和事务B请求的排他锁存在冲突,所以事务B需要等待事务A释放共享锁后才能修改数据。
阶段3:事务A查询price, price=10, 说明事务B的更新操作被阻塞了,更新操作没有被执行。然后事务A提交事务(COMMIT TRAN)
阶段4:事务A提交完事务后,释放共享锁
阶段5:事务B获得了排他锁,进行写操作,price=11
“可重复读 (REPEATABLE READ)”隔离级别的含义:
(1)必须获得共享锁才能进行读操作,获得的共享锁将一直保持直到事务完成之止。
(2)在获得共享锁的事务完成之前,没有其他事务能够获得排他锁修改这一数据资源,这样可以保证实现可重复的读取。
(3)两个事务在第一次读操作之后都将保留它们获得的共享锁,所以任何一个事务都不能获得为了更新数据而需要的排他锁,这种情况将会导致死锁(deadlock),不过却避免了更新冲突。
★ 4.可序列化(SERIALIZABLE)
打开两个查询窗口,Connetion1,connection2
Step1: 执行Connection1的SQL 语句
Step2: 执行Connection2的SQL 语句
执行语句 事务 执行语句
Connetion1 A
BEGIN TRANSACTION SET TRANSACTION ISOLATION LEVEL SERIALIZABLE SELECT * FROM dbo.myProduct WHERE id = 1
Connection2 B
INSERT INTO dbo.myProduct(id, price) VALUES (1, 20)
两个事务的流程图:
阶段1:Price=10,事务A对myProduct表请求共享锁
阶段2:事务A对myProduct表使用了共享锁,事务A查询id=1的price的价格:1行记录,price=10,事务A一直持有共享锁直到事务A完成为止。然后事务B请求排他锁进行插入操作id=1,price=20,
由于在当前隔离级别下,事务B试图增加能够满足事务A的读操作的查询搜索条件的新行,所以事务A的共享锁和事务B请求的排他锁存在冲突,事务B需要等待事务A释放共享锁后才能插入数据。
阶段3:事务A查询出id=1的数据只有1行,说明事务B的插入操作被阻塞了,插入操作没有被执行。然后事务A提交事务(COMMIT TRAN)
阶段4:事务A提交完事务后,释放共享锁
阶段5:事务B获得了排他锁,进行插入操作,插入成功,查询出id=1的数据有两条
“可序列化(SERIALIZABLE)”隔离级别的含义:
(1)必须获得共享锁才能进行读操作,获得的共享锁将一直保持直到事务完成之止。