例子如下:
begin tran
select @bh = bh + 1 from seed where mc = 'test'……(一些其他语句)update seed set bh = @bh where 
mc = 'test'if @@error <> 0 rollback trancommit tran这个事务应该会发生脏读的情况吧?
我想问的就是显示开始事务begin tran后, select 表seed,这时候的seed是不是加上共享锁了,另外一个事务的用户如果晚一点点读取了seed中bh的值,那这2个用户一提交事务,就会发生2个用户取到重复bh的情况了吧。如果是这样的话,在select @bh = bh + 1 from seed where mc = 'test' 前加:update seed set bh = bh where mc = 'nomc'这样是不是可以解决这个问题,如果能解决的话,这样会对其他方面有影响嘛?说得比较乱,希望各位大虾不吝赐教!

解决方案 »

  1.   

    SQL 默认隔离级别是提交读,未读交的更新是读不到的,select @bh = bh + 1 from seed where mc = 'test'……(一些其他语句)update seed set bh = @bh where  
    mc = 'test'
    这里没明白,如果中间没有影响BH值的话,直接
    UPDATE SEED SET Bh = bh + 1 from seed where mc = 'test'if @@error <> 0 rollback tran没错误就回滚?
      

  2.   

    很好的问题, 首先事务和锁是两个不同的东西。 事务的隔离级别决定了使用哪种锁。 像这个例子,你事务执行时, 你看下其它事务还能SELECT吗,应该是不可以的。 除非其他事务的隔离级别为read uncommited
      

  3.   

    TO:SQL77
    1、这里没明白,如果中间没有影响BH值的话,直接
    UPDATE SEED SET Bh = bh + 1 from seed where mc = 'test'中间一些其他语句对@bh影响了,所以不能像你那样2、if @@error <> 0 rollback tran没错误就回滚?@@error <> 0  不是表示有错么?难道我一直搞错了?
      

  4.   

    TO:budong0000
    想请问事务的隔离级别怎么设置? 我以前一直认为事务开始了如果没提交其他事务是不能读的,但是实际中我那个例子类似的一个存储过程就发生了两个用户获取到同一个BH了,我都弄糊涂了。
      

  5.   

    下面是我在网上看到的一段话,感觉的意思是事务执行时,其它事务还是能SELECT的:考虑使用乐观锁定或使事务首先获得一个独占锁定。一个最常见的死锁情况发生在系列号生成器中,它们通常是这样编写的: 
      
      begin tran 
      
      select new_id from keytab holdlock 
      
      update keytab set new_id=new_id+l 
      
      commit tran 
      
      如果有两个用户在同时运行这一事务,他们都会得到共享锁定并保持它。当两个用户都试图得到keytab表的独占锁定时,就会进入死锁。为了避免这种情况的发生,应将上述事务重写成如下形式: 
      
      begin tran 
      
      update keytab set new_id=new_id+l 
      
      select new_id from keytab 
      
      commit tran 
      
      以这种方式改写后,只有一个事务能得到keytab的独占锁定,其他进程必须等到第一个事务的完成,这样虽增加了执行时间,但避免了死锁。 
      
      如果要求在一个事务中具有读取的可重复能力,就要考虑以这种方式来编写事务,以获得资源的独占锁定,然后再去读数据。例如,如果一个事务需要检索出titles表中所有书的平均价格,并保证在update被应用前,结果不会改变,优化器就会分配一个独占的表锁定。考虑如下的SQL代码: 
      
      begin tran 
      
      update titles set title_idid=title_id . 
      
      where 1=2 
      
      if (selectavg(price)fromtitles)>$15 
      
      begin 
      
      /* perform some additional processing */ 
      
      end 
      
      update titles set price=price*1.10 
      
      where price<(select avg(price)from titles) 
      
      commit tran 
      
      在这个事务中,重要的是没有其他进程修改表中任何行的price,或者说在事务结束时检索的值与事务开始时检索的值不同。这里的where子句看起来很奇怪,但是不管你相信与否,这是迄今为止优化器所遇到的最完美有效的where子句,尽管计算出的结果总是false。当优化器处理此查询时,因为它找不到任何有效的SARG,它的查询规划就会强制使用一个独占锁定来进行表扫描。此事务执行时,where子句立即得到一个false值,于是不会执行实际上的扫描,但此进程仍得到了一个独占的表锁定。 
      

  6.   

    SET TRANSACTION ISOLATION LEVEL
        { READ UNCOMMITTED
        | READ COMMITTED
        | REPEATABLE READ
        | SNAPSHOT
        | SERIALIZABLE
        }
    [ ; ]
    具体含义,LZ网上搜索下吧
      

  7.   

    是否出现脏读与事务的隔离级别有关,
    默认的隔离级别为读提交,
    可能出现LZ所说的情况,发出脏读.
    LZ所述的情况,要保证无脏读,应将隔离级别设为
     REPEATABLE READ 或 SERIALIZABLE
    保证读过的数据不要被别的事务修改.最好在读记录的语句中加排它锁,保证读过后别的事务不能再读,以保证
    update能顺利提交.因为将事务隔离级别设为repeatable read后,虽可保证读过后数据不会被别的事务修改,但其它事务仍可读取数据,如果隔离级别相同,那么两个事务都update不了,变为死锁.