数据库事务隔离性和锁,加深理解

简介:

1.假设有一个事务A

1
2
3
4
5
6
-----事务A------- 
begin  tran 
update  [TestDB].[dbo].tb_score  set  score=score+1  where  id=3 
    waitfor delay  '00:00:10'    --延迟10秒读取 
SELECT  *   FROM  [TestDB].[dbo].tb_score 
commit  TRANSACTION


它会运行10s左右,主要是更新表tb_score。在这10s期间,有语句对该表做查询。

1
SELECT  *   FROM  [TestDB].[dbo].tb_score

该语句会被阻塞,因为update会默认加上共享锁,直到10s后,事务A提交后才能查出结果。

以上语句就等介于下面的语句,因为事务隔离级别READ COMMITTED是SQLServer的默认设置。

1
2
3
4
5
SET  TRANSACTION  ISOLATION  LEVEL 
READ  committed 
begin  tran 
SELECT  *   FROM  [TestDB].[dbo].tb_score 
commit  TRANSACTION


此处,值得注意的事情是,在事务A中当update语句更新的时候,如果要更新的目标值=现在的值,比如,在id=3的记录,score已经等于100了的情况下,语句如果是update [TestDB].[dbo].tb_score set score=100 where id=3。那么执行SELECT *  FROM [TestDB].[dbo].tb_score将不被阻塞。原因猜测是sql不对这种实际不做更改的Update语句加锁

     

2.还是以上事务A

把查询语句改为如下

语句B:

1
2
3
4
5
SET  TRANSACTION  ISOLATION  LEVEL 
READ  uncommitted 
begin  tran 
SELECT  *   FROM  [TestDB].[dbo].tb_score 
commit  TRANSACTION

此时

SELECT *  FROM [TestDB].[dbo].tb_score语句被允许“脏读”

该查询未等事务A提交,就已经读出,并且读书的值为A以修改但未提交的值。

例如id=3的score=100,运行A事务的时候,score=101了,此时运行语句B,则立刻返回出id=3的score=101,而不管A是否真的已经提交或者rollback。

还有一点要注意,当你设置了READ uncommitted,那么接下来的sql语句都会是 READ uncommitted。msdn上:一次只能设置一个隔离级别选项,而且设置的选项将一直对那个连接始终有效,直到显式更改该选项为止。事务中执行的所有读取操作都会在指定的隔离级别的规则下运行,除非语句的 FROM 子句中的表提示为表指定了其他锁定行为或版本控制行为。所以在查询分析器中做实验的时候,要注意,一旦设置了READ uncommitted,接下来在当前窗口中的语句都是如此。

3

1
2
3
4
5
-----事务A------- 
begin  tran 
select  * from   [TestDB].[dbo].tb_score  with (tablockx)  where  id=3 
    waitfor delay  '00:00:10'    --延迟10秒读取 
commit  TRANSACTION


此事务对表加了表级别的排它锁。因此在此期间,

1
2
3
4
5
SET  TRANSACTION  ISOLATION  LEVEL 
READ  uncommitted 
begin  tran 
SELECT  *   FROM  [TestDB].[dbo].tb_score  where  id=1 
commit  TRANSACTION

更多内容,可以看

http://msdn.microsoft.com/zh-cn/library/ms187373.aspx

http://msdn.microsoft.com/zh-cn/library/ms173763.aspx    

4

此处有些疑问:

两个事务   

1
2
3
4
5
6
7
8
9
10
11
-----事务A-------
  begin  tran 
  select  * from   [TestDB].[dbo].tb_score  with (updlock,rowlock)  where  id=3    waitfor delay  '00:00:10'    --延迟10秒读取 
  update   [TestDB].[dbo].tb_score  set  score=score+1   where  id=3  commit  TRANSACTION
 
-----事务B------ 
SET  TRANSACTION  ISOLATION  LEVEL  READ  committed 
begin  tran 
select  * from   [TestDB].[dbo].tb_score  with (updlock,rowlock)  where
id=3
commit  TRANSACTION

我的理解是,事务A运行的时候,对id=3的加了行锁,还有更新锁,更新锁的话一定要等到事务运行完才能再被获取。   
因此事务A运行的时候,事务B也马上运行,但是事务B也要对改行获取更新锁,因此被阻塞在此,所以最后运行的结果是A运行完了B在运行。以上一切正常

但是把事务B改成   

-----事务B------- 

1
2
3
4
SET  TRANSACTION  ISOLATION  LEVEL  READ  committed 
begin  tran 
select  * from   [TestDB].[dbo].tb_score  with (updlock,rowlock)  where  id=1
commit  TRANSACTION

事务B对id=1的行加锁。   
那么我的理解是,既然事务A加锁的对象是id=3的行,那么和事务B根本不会有什么冲突。但是事实上,运行事务A后马上运行B,发现事务B也会被阻塞。并且事务A还会发出异常错误:说是检测到死锁。    
Transaction (Process ID 52) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction.

本人愚钝,百思不解,求专家指教。
























本文转自cnn23711151CTO博客,原文链接:http://blog.51cto.com/cnn237111/638055 ,如需转载请自行联系原作者







相关文章
|
1月前
|
SQL 关系型数据库 数据库
事务隔离级别:保障数据库并发事务的一致性与性能
事务隔离级别:保障数据库并发事务的一致性与性能
|
1月前
|
算法 大数据 数据库
数据库事务:保障数据一致性的基石
数据库事务:保障数据一致性的基石
|
1月前
|
SQL 存储 关系型数据库
【MySQL 数据库】11、学习 MySQL 中的【锁】
【MySQL 数据库】11、学习 MySQL 中的【锁】
75 0
|
1月前
|
供应链 数据库 开发者
深入了解数据库锁:类型、应用和最佳实践
深入了解数据库锁:类型、应用和最佳实践
|
4月前
|
存储 关系型数据库 MySQL
了解MySQL 数据库的锁机制
了解MySQL 数据库的锁机制。
38 0
|
4月前
|
存储 SQL 关系型数据库
认识数据库中的事务机制
认识数据库中的事务机制
19 0
|
4月前
|
SQL 存储 关系型数据库
认识数据库中的事务机制(2)
认识数据库中的事务机制(2)。
37 0
|
1月前
|
存储 关系型数据库 MySQL
最全MySQL面试60题(含答案):存储引擎+数据库锁+索引+SQL优化等
最全MySQL面试60题(含答案):存储引擎+数据库锁+索引+SQL优化等
154 0
|
4月前
|
监控 NoSQL Java
Redis数据库 | 事务、持久化
Redis数据库 | 事务、持久化
28 0
|
1月前
|
SQL 关系型数据库 MySQL
【MySQL 数据库】4、MySQL 事务学习
【MySQL 数据库】4、MySQL 事务学习
44 0