把Transcation Level改成READ COMMITTED就可以啦SET TRANSACTION ISOLATION LEVEL  READ COMMITTED

解决方案 »

  1.   

    感谢这位兄弟!
    我试验了一下,结果还是不行(真遗憾)
    试验结果如下 
      程序A 插入20000行,在运行的过程中执行程序B(插入30行)
    结果是B的30条被分成3部分保存在数据表中
    麻烦您老再帮俺想想?
      

  2.   

    想起來了,這問題跟Trancation ISOLATION 沒關系。
    好像是要把這SP做到一個工作里面,使SP在同一時間點只能有一個人使用。
    (好像是這樣…等高手來吧*_)
      

  3.   

    一劍飄香兄,给点思路好吗?一定给分的
    这个问题其实对于处理并发挺重要的
    我还有一个发现,在存储过程里如果不写
    SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
    则type=b的记录的id列是 2,4,6,8,10(type=a的是1,3,5,7,9)
    但是如果加上了
    SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
    则type=b的记录的id列是 1,2,3,4,.....11,23,24,25....\
    每11个记录一组
      

  4.   

    现在sqlserver版块的讨论风气不错,有一些比较深入的讨论,很让人高兴。
    littleLiu(小刘),你的探索精神很好,多用些例子实践,然后通过现象看本质,就能更好地搞清楚数据库的原理。
    你所说的问题,我就我的理解给你一些提示:
    一般来说对于数据库的插入操作,如果指定了事务隔离级别为SERIALIZABLE,sqlserver是使用了一种叫做键范围锁的事务锁来进行锁定的。当要插入记录时,sqlserver先使用RangeI_N模式键范围锁放置在对应于要插入记录的索引项上以测试范围。如果已授权锁定,则插入记录,并且把排它 (X) 锁放置在该记录上,一般为页锁。这时,其他事务要插入记录,使用RangeI_N模式键范围锁来测试时将得不到授权,只有到一个数据页已经添满记录以后,另一个事务才可能得到授权,开始插入记录,这时,前一个事务使用的RangeI_N锁又开始等待了。所以出现了你说的id号批量交替的现象,10条左右的记录应该包括在同一数据页中。
    如果你没有设置SERIALIZABLE的事务隔离级别,则每个插入操作相当于一个隐形的事务,插入一条提交一次,所以id号交替也就很正常了。不知道这么说,你是否明白,建议你不光测试插入操作,SERIALIZABLE的事务隔离级别最大的特点在查询控制,防止出现幻影行,你删,改,查也可以试试,从多方面来了解sqlserver对事务的管理。
      

  5.   

    蓝色力量,承蒙您夸奖,也非常感谢您的帮助。
    您写的内容除了一些名词(RangeI_N模式?隐形的事务?)我不太明白以外
    其余的都看懂啦!(您老人家要是写书,一定告诉我一声哦,很容易懂的)经过测试,我确实发现SERIALIZABLE和READ COMMITTED的不同
    您看我的理解对不对READ COMMITTED级别是当一个事务(假设是事务A)设定了这种级别,
    其它的事务(事务B)只能读但不能写(初学,用词不当您见谅)
    而且事务A是一个插入操作的话,事务B在事务A运行期间执行,
    所得到的查询结果中不包括事务A刚刚插进来的数据SERIALIZABLE则是跟本就不能查询,是吧!另外我还有问题,就我提出的问题而言,
    我的实验是插入20000条数据,而目前看来,每一个数据页是10条左右
    记录,那么假如我的两个程序分别是插入9条和2条,那么后运行的
    插入2条的记录就应该是在9条数据之后,是吗?(假设操作速度足够快
    ,当插入9条记录的程序没运行完就执行了插入2条记录的程序)还有,可以用sql语句或者在存储过程中设定数据页的大小吗?比如
    设成50条?
      

  6.   

    littleLiu(小刘):可以看出你对事务级别已经有了一定的了解,但有些小地方理解可能还有偏差。
    首先,我们要明白事务隔离级别主要解决的是什么,是并发操作问题。而并发操作中的关键,除了两个进程同时修改或删除某条记录以外,最重要的是一个进程查询另一个进程正在修改或删除的记录的问题。对于同时修改某条记录的问题,有排他锁来保证,问题不是很大,因此事务隔离级别要解决的是读取正在修改的记录,导致得到的数据和实际不一致的现象。
    我们可以先分析一下都会有什么情况出现:
    假设有两个事务A和B,A主要是读取记录,B则是正在修改A要读取的记录。
    1。有一条记录B正在修改,还没有提交,这时A把这条没有提交的记录读取走了,而B因为其他语句执行失败,回滚了事务,那么A读取的这条记录实际在数据库中已经不存在,这就会导致数据不一致,这种读取数据的方式叫脏读。
        以上问题的解决办法就是事务A在读取数据的时候先设置一个共享锁,设置这个共享锁,有两个目的,一是如果读取的记录正在被事务B修改,还没有提交,则事务A是无法获取共享锁,只能等到B提交完后才能读取,从而避免脏读的现象出现;同时,当A已设置上共享锁,在读取期间,B是无法再进行修改。
        这种事务隔离级别就是READ COMMITTED,是sqlserver默认的隔离级别。
    2。以上方式可以保证没有脏读,但是也有其他问题,因为当事务A查询多个结果集时,每执行完一条SQL语句,所设置的共享锁就会释放,而事务B也就可以修改A已读取的记录。如果A读取了一条记录,然后释放共享锁,B马上修改了这条记录,A在随后又读取了一次这条记录,就会出现两次读取记录不一致的情况,这就是不可重复读取数据;另外还有一种情况,A读取了大于1小于10之间的一批数据,然后用共享锁锁住这批数据,但是只能保证B不修改和删除这些数据,但B可以插入数据,比如插入原先不存在的5这条数据,这时A再次读取大于1小于10之间的数据时就会多出一条记录,造成不一致,这种数据叫幻像数据。
        以上问题的解决方法就是将事务A中读取的所有数据都设置共享锁,并且在事务结束前一个都不释放,这样就可以保证已读取的数据不能被修改和删除,但对于增加数据这种情况,sqlserver采用的解决办法就是我跟你说的范围锁,把查询的这个范围(1-10)加上锁,插入的数据在范围锁锁定的区域就不执行,保证没有幻像数据产生。
        这种事务隔离级别就叫SERIALIZABLE,是最严格的隔离级别,相当于在事务内所有 SELECT 语句中的所有表上设置 HOLDLOCK。
        但这种方式只是放置共享锁,其他事务读取还是可以的,不是根本没法查询。
        
        至于设置数据页大小的问题,这是sqlserver物理构架的一部分,一页8K,是没法更改的。
        如果你一定想要先执行完一个事务,再执行另一个事务,可以在插入语句前先执行一条查询语句,把整个表锁住,然后再插入,不过这种方法我没有试过,你可以试试看。
      

  7.   

    學習!!!另:想請教藍大哥一個問題:   有一個Com+元件,其屬件設為了RequireTrancation,即里面所有對後端資料庫的異動都得需要一個Trancation,而這COM元件里面的一個Function調用了SQL Server端的一個Stored Procedure,在這個SP里面又有自己用BEGIN TRAN定義了几個Trancation。
       那麼它們之間是怎樣協調這些交易的??謝謝。
      

  8.   

    如果在元件那邊由於某種原因執行了
    ObjectContext.SetAbort
    而且SP里所有的Trancation都已經提交
    那麼SP對資料庫的修改是否有效?
      

  9.   

    最近我在學COM+,被它里面的交易控管實在是搞得頭大。
      

  10.   

    begin tran commint tran
    的默認值是什么呀?
      

  11.   

    TO  N_chow(一劍飄香++):
    据我的理解,如果一个Transaction没有执行到committed,那么是会RollBack的,也就是说, 
     当你的元件那邊由於某種原因執行了
    ObjectContext.SetAbort
    而且SP里所有的Trancation都已經提交
    这时SP對資料庫的修改也是无效的。
    TO dreamyyuan(dreamyyuan):
    蓝兄已经说得很清楚了,SQL 2000的Default值是READCOMMITTED.
    TO LittleLiu:
    如果一定要达到你想要的结果,你可以使用TABLOCKX。该锁可以防止其它事务读取或更新表,并在语句或事务结束前一直持有。
     
    我也在学习这方面的东东,如果有错误,请大家指正。