读污染(dirty reads)
一个事务读取了另一个未提交的并行事务写的数据。 不可重复的读(non-repeatable reads)
一个事务重新读取前面读取过的数据, 发现该数据已经被另一个已提交的事务修改过。 错误读取(phantom read)
一个事务重新执行一个查询,返回一套符合查询条件的行, 发现这些行中插入了被其他已提交的事务提交的行

解决方案 »

  1.   

    请问他们是在什么情况下出现??怎么预防?? thanks
      

  2.   

    这算两个问题要加分。
    隔离级别       读污染             不可重复的读            错误读取  
      
    读未提交(Read uncommitted)  可能     可能              可能  
    读已提交(Read committed)    不可能  可能                 可能  
    可重复读(Repeatable read)   不可能  不可能               可能  
    可串行化(Serializable )     不可能   不可能                不可能  
      

  3.   

    举个例子:dirty read     脏读1 、什么是 dirty read ? 它是怎样产生的? 
    2 、dirty read 会产生什么后果?
    3 、dirty read 怎样才能避免?
      

  4.   

    一般来说,SQL Server的内定是Read Committed,Informix Dynamic Server中如果该
    Database有Log亦是Read Committed,否则是Dirty Read。看一下以下的例子 Process A 和Process B同时执行以下的程序片断
       Set en = rdoEnvironments(0)
       Set cn = New rdoConnection
       cn.CursorDriver = rdUseServer
       connstr = "DSN=SQLSRV;UID=cww;PWD=jjh5612;"
       cn.Connect = connstr
       cn.EstablishConnection rdDriverNoPrompt, False
       sql = "Select * From testtab"
       Set qry = cn.CreateQuery("MyQuery", sql)
       qry.SQL = "Select * from testtab"
       Err.Clear
       rdoErrors.Clear
       On Error GoTo Errhandle 
     1. cn.BeginTrans 
     2. qry.RowsetSize = 1
     3. Set rs = qry.OpenResultset(rdOpenKeyset, _
            rdConcurValues)
     4. rs.MoveLast
     5. rs.Edit
     6. rs.rdoColumns(1) = "o"
     7. rs.Update
     8. If rdoErrors.Count <> 0 Then
     9.    cn.RollbackTrans
    10. Else
    11.   cn.CommitTrans
    12. End IfErrhandle :
      
     
     
    情况一:
    如果Process A已执行到行号8 的if rdoErrors.Count <> 0 then,而Process B方要执
    行号3的OpenResultset,结果会如何呢?因为Process A在最后一笔加以Update,而且
    Transaction尚未结束,而rdOpenKeyset的方式会把Table从头扫到尾,扫到最后一笔时
    发现该笔Data尚未Committed(有个Exclusive Lock於其上),又加上内定的Read Committed
    ,结果变成是Process B执行到OpenResultSet会停住(我没有用非同步开启),它在等那
    一笔被Exclusive Lock的资料解锁,等到TimeOut时,便会产生ErrorSQL Server Error
        rdoErrors(0).Number:40087  执行动作被取消,
        rdoErrors(1).Number:0      S1008: [Microsoft][ODBC SQL Server Driver]
                                          Operation canceled
        Err.Number = 40087
    Informix Error
        rdoErrors(0).Number:0      37000: [OpenLink][ODBC][Driver]Syntax error 
                                          or access)
        Err.Number = 40002
    情况二:
    如果Process A执行到行号6,而Process B执行完行号3,Process A执行完行号7之Update
    指令(此时Transaction未结束)而Process B执行MoveLast时会进入等待,Timeout时会有
    Error,这是因为Read Committed之故,而情况一多了一个Share Lock的问题,而这里因
    为乐观锁定在读出资料后就没有Lock,所以没有Share Lock的问题。SQL Server Error
        rdoErrors(0).Number:0      S1T00: [Microsoft][ODBC SQL Server Driver]
                                          Timeout expired
        Err.Number = 40002Informix Error
        rdoErrors(0).Number -243   S1000: [OpenLink][ODBC][Informix Server]
                                          Could not position within a table 
                                          (cww.testtab). (-243
        Err.Number = 40002
      

  5.   

    情况三:
    如果Process A执行到行号6,而Process B执行到号6,Process A执行完行号7之Update
    指令(此时Transaction未结束)而Process B执行Updtae时会进入等待,等到TimeOut时
    产生另一种错误讯息,但这里要注意,Informix没有产生err的错误,只是rdoErrors
    有东西,也就是说,这类的错误不能用On Error的方式来拦截。SQL SERVER Error
        rdoErrors(0).number 16934  01S03: [Microsoft][ODBC SQL Server Driver]
                                          [SQL Server]Optimistic concurrency check
                                          failed, the row was modified outside of 
                                          this cursor
        Err.Number = 40041 Informix Warnning
         rdoErrors(0).Number 0     37000: [OpenLink][ODBC][Driver]Syntax error 
                                          or access
         rdoErrors(1).Number -243  S1000: [OpenLink][ODBC][Informix Server]
                                          Could not position within a table
                                          (cww.testtab). (-243
         Err.Number = 0情况四:
    如果Process A执行到行号8,也就是说在最后一个Row上有一个Exclusive Lock,而
    Process B 执行行号3,但是改成
       Set rs = qry.OpenResultset(rdOpenForwardOnly, rdConcurValues)
    那麽到底有没有可能有错?答案是不一定,如果这rdOpenForwardOnly的Resultset不用
    Scan table,或者不用读到被Lock的那一笔Data,便可Open 成功者,那这OpenResultSet
    不会有任何等待而成功。如果说,就算被Lock住的那一笔不在目前Process的Resultset之
    中,但因为要Scan过它才知有或没有在Resultset中,那麽,这OpenResultset的动作也会
    进入等待。如果是Page Lock的情况,那影响的Row就更多了。看完上面的数种情况,不难知道Currency的Handle真的好麻烦,重点在於Transaction
    的时间不可过久,以免被Lock住而产生Error。上面所提的都是Read Committed的情况,而Dirty Read / Repeatable Read呢?我们来
    如何设定这二者?首先建立起Connection,再来使用Transaction,最后设定之,如下
      Set en = rdoEnvironments(0)
      Set cn = New rdoConnection
      cn.CursorDriver = rdUseServer
      connstr = "DSN=SQLSRV;UID=cww;PWD=jjh5612;"
      cn.Connect = connstr
      cn.EstablishConnection rdDriverNoPrompt, False
      sql = "Select * From testtab"
      Set qry = cn.CreateQuery("MyQuery", sql)
      qry.SQL = "Select * from testtab"
      Err.Clear
      rdoErrors.Clear
      On Error GoTo Errhandle 
      cn.BeginTrans 
    '-----------就在这里了 ----------------------------------------------------
    '  cn.Execute "Set TRANSACTION ISOLATION LEVEL Repeatable READ", rdExecDirect
    '  cn.Execute "Set TRANSACTION ISOLATION LEVEL READ UNCOMMITTED", rdExecDirect
    '  cn.Execute "Set TRANSACTION ISOLATION LEVEL READ COMMITTED", rdExecDirect
    '--------------------------------------------------------------------------  
     Set rs = qry.OpenResultset(rdOpenKeyset, _
            rdConcurValues)可以把想要的方式UNMARK,如果说使用的是Read Uncommitted的方式,那是不管他人有没
    有在Record上做Lock,先读了再说,所以情况一、情况二都不会有Error产生,只不如果  
    以Read Uncommitted的方式开启的Cursor,它只能是ReadOnly的Cursor,它是不能用来修
    改的。如果说使用的是Repeatable Read的方式,它和悲观锁定有一点像,又不太像,Repeatable
    Read的方式在开启Cursor时,会在它曾读取过的资料上做Share Lock,也就是说,如果所
    要的资料需Scan table(没有用到Index),那麽,不管该资料有没有在Resultset之中,只
    要读取过,便在上面做一个Share Lock(而悲观锁定则是Update Lock),如果有用上Index
    的Cursor状况就比较好,不在Resultset的Row不会有Share Lock(如果是Page Lock那就未
    必了)。为什麽Repeatable Read这麽"龟毛",人家不在Resultset中的也想要在其上做一
    个Share Lock?其实有它的道理,Repeatable Read保证在Cursor Open期间读过的资料会
    固定,不允许他人突然更新/新增资料,而使该Data会落在Resultset之中。我还是觉得这
    样做不是方便啦。Repeatable Read做的是Share Lock 因此,可以有两个Cursor同时以
    Repeatable Read的方式来Open相同的Resultset(和悲观锁定不同)。就是因为Repeatable
    Read有这麽多的限制,它大量降低Concurrency,所以实作上很少这样子做。Informix则在Set Transaction Isolation Level之外多新增了 Set IsolationSet Transaction         相对於    Set Isolation
    -----------------                 -------------------
    Read Uncommitted                  Dirty Read
    Read Committed                    Committed Read
    没提供                            Cursor Stability
    Repeatable Read                   Repeatable Read 设定的方式是
    cn.Execute "SET ISOLATION TO CURSOR STABILITY", rdExecDirect
    cn.Execute("SET ISOLATION TO DIRTY READ", rdExecDirect
    cn.Execute("SET ISOLATION TO REPEATABLE READ", rdExecDirect
    cn.Execute("SET ISOLATION TO COMMITTED READ", rdExecDirect直接把以上的方式取代
     cn.Execute "Set TRANSACTION ISOLATION LEVEL ...
    的位置便可以。Informix的 Cursor Stability是介於Read Committed与Repeatable Read的一个方式,
    Cursor Stability是在Current Record上有一个Share Lock,当读取到其他笔时便Release
    现有的Lock,而在新的资料上做Share Lock(基本上它也必需有Read Committed的功能)。
    当然了,如果您将Current Record Update了,那会在该笔之上有一个Exclusive Lock
    ,一直到Transaction结束,这和Committed read / Repeatable Read没有不同。这里要
    注意,不管是Repeatable Read/ Cursor Stability的Cursor,在Transaction结束时,会
    把所有的Lock Release;在SQL SERVER呢,Transaction结束时也就没有Current Recotrd
    了,但Informix则不同,Transaction结束了,所有Lock 了,但是仍有Current Record
    ,那应该是OpenLink的Informix ODBC Driver对於Server端的Cursor是以Hold Cursor
    的方式来建立之故(Hold Cursor指的是在Transaction结束时,仍保有Currenmt Record)。
    即然知道设定Cursor Stability后的Cursor是在Current Record上做Share Lock,那麽
    其他的例子就不再多做说明,可以自行研究。不过我们查Informix的手册,人家会告诉我们,如果Cursor可用来Update,那Repeatable
    Read/Cursor Stability会在目标Object上放Update Lock而不是Share Lock,但使用ODBC
    来做时,其结果是我上面所说的Share Lock,这中间的原因我不是很清楚。 上面的例子中说到Informix 读取资料时也会等待Lock的的Release,不过内定是没有这
    样子做,但我们可以用以下的方式来改cn.Execute "Set Lock Mode to Wait"         设定遇Lock则无限等待
    cn.Execute "Set Lock Mode to Not Wait"     遇Lock则不等待,立即产生Error
    cn.Execute "Set Lock Mode to Wait 10"      等待10秒,若未能读取成功才产生Err它放的位置没有太多的限制,只要是Connection建立起来后便可,而且执行后立即生效。
    一般我会放在OpenResultset之前,因为OpenResultSet是第一个会读取资料的方法。透
    过OpenResultset的Server端Cursor来做Insert/Update/Delete/Move时,正常情况以下
    每一个步骤都得有一段Error Check的动作以防concurrency所造成的问题。OpenResultset
    Move 系列
    Update/AddNew/Delete
    Cursor有Lock,便会降低Concurrency,这不是一件好事,而且Lock会花费系统的资源,而
    且我们也很难去知道DBMS到底Lock住了多少Row,而且不能保证重新执行时Lock的状态
    会和上次相同。因此能不Lock就不要用Cursor Stability来做(更不用说Repeatable Read)
    ,另外,能不用Scroll Cursor做就不要用之,因为它花费Resource而且也会降低Concurrency
    ;如果是一个查询用的Cursor,大可以用rdUseNone的方式来开Cursor,那才是正途。
    最后,如果不得以,一定得用Scroll Cursor,能Readonly那也会比较好,如果ReadOnly
    也不成,那要想办法降低Resultset内的笔数,但也顾及Index的使用(否则table Scan就
    更惨)。见了以上及前几篇文章的说明,您相信透过ODBC连接后端数据库时,若想改变后端的数据库,
    会只是单纯的改Connection字串而以吗?我想不见得吧,说不定还得花很多的时间来testing
    新的ODBC Driver之特性与后端RDBMS的功能呢!因此最好的方式是使用最单纯的做法来做
    ,最单纯的部份理论上各个后端与各个ODBC Driver都相同的。
      

  6.   

    TO:zmcpu(CPU)想给你100分

    为什么系统提示俺只能给20分 ????