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锁?
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锁?
不会我看过它是加的行X锁,在表上加的IX锁,而且我试过了执行update T_A set name='BBB' where name='CCC' 因为CC并没有被加锁
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' --不阻塞
为什么?
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'这两个都会被阻塞,访问的是同一个页面,自然会被阻塞。因为你第一个未提交的事务已经在这个页面上加锁
那么,对于在 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 跟踪一下,可以看得更明白。
恩是不是就是意味着第一个事务的begin tran update T_A set name='AAA1' where name='AAA' 相当于数据库里临时多了一行叫'AAA1'?并且AAA1和AAA都加上了X锁?
并不是针对某条记录行加锁.
往更深的讲,这个涉及到数据库存储引擎执行的是“就地更新”,还是“删除-插入更新”。
对于 lz 的情况,在没有索引时,update 直接用新的数据替换旧的;在有索引时,update 会根据索引,先将新的数据插入索引中适合的位置,再去删除旧的(当然在事务提交后)。