事务里执行update的疑问

BusyDonkey 2009-12-14 10:59:28
begin tran
update T_A set name='AAA1' where name='AAA'

执行事务后没提交,那么数据库里面是AAA还是AAA1?
如果这时我再启动个事务(已在name上用了聚集索引)
SET TRANSACTION ISOLATION LEVEL READ COMMITTED

begin tran
update T_A set name='BBB' where name='AAA1'
update T_A set name='BBB' where name='AAA'

执行上面两句后都会被阻塞,是否代表第一个事务执行update后数据库中有AAA和AAA1两条数据并都加了X锁?
...全文
203 14 打赏 收藏 转发到动态 举报
写回复
用AI写文章
14 条回复
切换为时间正序
请发表友善的回复…
发表回复
lrjt1980 2009-12-14
  • 打赏
  • 举报
回复
挺难。
xman_78tom 2009-12-14
  • 打赏
  • 举报
回复
事务的隔离性。在读已提交事务隔离级别中,在事务未提交前,在事务中修改的结果只能在该事务中被读取,对于其他事务都是不可见的。
那么,对于在 name 上有索引的情况,下面的现象
update T_A set name='BBB' where name='AAA1' --阻塞
update T_A set name='BBB' where name='AAA' --阻塞
是 SQL Server 在事务未提交前对 AAA 和 AAA1 都保持有 X 锁,阻塞其他事务对这两个记录的访问。LZ 可以用 SP_LOCK 存储过程验证一下。
如果在 name 上没有索引,则 SQL Server 只对 AAA 行保持有 X 锁(RID 锁)。那么,在使用上面两条语句更新时同样会被阻塞。只不过是在更新 AAA1 记录时,在进行表扫描查找 AAA1 时被 AAA 上的 X 锁阻塞的。
不知道我解释的清不清楚?LZ 可以通过 Profiler 跟踪一下,可以看得更明白。

  • 打赏
  • 举报
回复
1、楼主先看下你这个表的有几个数据页,
begin tran
update T_A set name='AAA1' where name='AAA'
应该是对这个数据所在的页进行了加锁,而update T_A set name='BBB' where name='CCC' --不阻塞
可能是因为这个数据在另一个页面,而没有被锁,所以没有阻塞

2、SET TRANSACTION ISOLATION LEVEL READ COMMITTED

begin tran
update T_A set name='BBB' where name='AAA1'
update T_A set name='BBB' where name='AAA'

这两个都会被阻塞,访问的是同一个页面,自然会被阻塞。因为你第一个未提交的事务已经在这个页面上加锁
xiequan2 2009-12-14
  • 打赏
  • 举报
回复
sql的默认是已提交读,默认情况下是锁定整个表,当在表上建有聚集索引的时候,锁的粒度会改变,会在行集上产生锁
忆轩辕 2009-12-14
  • 打赏
  • 举报
回复
我的感觉是SQL SERVER虽然支持行锁,但是实际上不完全支持,这种情况下,name上有聚集索引,所以加了键锁,是一部分数据被锁了,而不是只有一行被锁
BusyDonkey 2009-12-14
  • 打赏
  • 举报
回复
现在的问题就是:
begin tran
update T_A set name='BBB' where name='AAA1' --阻塞
update T_A set name='BBB' where name='AAA' --阻塞
update T_A set name='BBB' where name='CCC' --不阻塞
为什么?
BusyDonkey 2009-12-14
  • 打赏
  • 举报
回复
而且我试过了执行update T_A set name='BBB' where name='CCC' 没被阻塞因为CCC并没有被加锁
BusyDonkey 2009-12-14
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 guguda2008 的回复:]
应该是整个表都给锁了吧。。。。。
[/Quote]

不会我看过它是加的行X锁,在表上加的IX锁,而且我试过了执行update T_A set name='BBB' where name='CCC' 因为CC并没有被加锁
fwacky 2009-12-14
  • 打赏
  • 举报
回复
和事务有关的,所有锁定!
SQL77 2009-12-14
  • 打赏
  • 举报
回复
如果一条有错,要回滚的话,都会回滚的
guguda2008 2009-12-14
  • 打赏
  • 举报
回复
应该是整个表都给锁了吧。。。。。
xman_78tom 2009-12-14
  • 打赏
  • 举报
回复
在事务未提交前,是这样的。
往更深的讲,这个涉及到数据库存储引擎执行的是“就地更新”,还是“删除-插入更新”。
对于 lz 的情况,在没有索引时,update 直接用新的数据替换旧的;在有索引时,update 会根据索引,先将新的数据插入索引中适合的位置,再去删除旧的(当然在事务提交后)。
幸运的意外 2009-12-14
  • 打赏
  • 举报
回复
数据库更新时,封锁等级是比较高的read comment,也就是,在事务结束前,对该表的所有访问是不允许的.
并不是针对某条记录行加锁.
BusyDonkey 2009-12-14
  • 打赏
  • 举报
回复
[Quote=引用 10 楼 xman_78tom 的回复:]
事务的隔离性。在读已提交事务隔离级别中,在事务未提交前,在事务中修改的结果只能在该事务中被读取,对于其他事务都是不可见的。
那么,对于在 name 上有索引的情况,下面的现象
update T_A set name='BBB' where name='AAA1' --阻塞
update T_A set name='BBB' where name='AAA' --阻塞
是 SQL Server 在事务未提交前对 AAA 和 AAA1 都保持有 X 锁,阻塞其他事务对这两个记录的访问。LZ 可以用 SP_LOCK 存储过程验证一下。
如果在 name 上没有索引,则 SQL Server 只对 AAA 行保持有 X 锁(RID 锁)。那么,在使用上面两条语句更新时同样会被阻塞。只不过是在更新 AAA1 记录时,在进行表扫描查找 AAA1 时被 AAA 上的 X 锁阻塞的。


不知道我解释的清不清楚?LZ 可以通过 Profiler 跟踪一下,可以看得更明白。
[/Quote]

恩是不是就是意味着第一个事务的begin tran update T_A set name='AAA1' where name='AAA' 相当于数据库里临时多了一行叫'AAA1'?并且AAA1和AAA都加上了X锁?

34,588

社区成员

发帖
与我相关
我的任务
社区描述
MS-SQL Server相关内容讨论专区
社区管理员
  • 基础类社区
  • 二月十六
  • 卖水果的net
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧