分类:
2009-10-11 11:36:57
来源:CWW 上回提到了OpenResultset方法,可以有以下数种型态的Cursor rdOpenForwardOnly rdOpenStatic rdOpenDynamic rdOpenKeyset 也提及了SQL Server/ Informix的Server/Client端Cursor与之搭配的记录,再来讨论 OpenResultset的 LockType,这LockType的设定主要是为了多人同时使用的环境而设。 rdConcurReadOnly 1 (预设值)唯读的。 rdConcurLock 2 悲观的平行。 rdConcurRowVer 3 基於资料列 ID之乐观的平行。 rdConcurValues 4 基於资料列值之乐观的平行。 rdConcurBatch 5 使用批次模式更新之乐观的平行处理。为每一笔成功地被 更新的资料列传回 Status 值。 而我们这里针对的是前4者加以讨论。 如果是rdUseODBC 的Client端Cursor,上回提过,它只能有rdOpenForwardOnly 及 rdOpenStatic两种型态(使用其他型态时,可能也不会有误,但行为只有这两种模式) 而使用的锁定模式呢,只能是rdConcurReadOnly/rdConcurValues 而其他的锁定模式呢 使用下去,可能会有错,也可能没有,那要看ODBC Driver的厂商如何写,但其锁定行模 式应只有上述说的这两种(rdConcurBatch我未研究)。 如果是Server端的Cursor(rdUseServer),那才能使用这前四种锁定方式;rdConcurReadOnly 不用多说,那代表该Cursor不是Update Cursor,只能读取。而rdConCurLock是悲观的锁 定,根据我的Testing ,SQL Server6.5 其悲观的锁定的特性是:只要在OpenResultset 时,者就会在RowSetSize数目的列上做一个Update Lock,如果是Page Lock的状态,那 至少会把各个Row所在的Page上的列全Lock住,因此Lock住的列可不只RowSetSize的数目 。当然,这只是某些情况之下会如此,SQL SERVER会看实际的情况来Handle Lock,说不 定会Lock整个Table也不一定。这里要提一下Lock的种类: Share Lock : 同时之间有很多Procee可以Share Lock住某一笔资料,一般读取时有时会 在上面做个Share Lock(并不是每一种都会,要看我们先前的设定) Exclusive Lock : 某一笔Record不能有其他的任何Lock(含Share Lock)时,才能Lock成, 一般在update/delete等动作时,会先Exclusive Lock该笔,成功时才能再 做往後的动作。 Update Lock:或称Promotable Lock,这个Lock是为了Current Record有所更动而设计, 它允许Share Lock与之共存,但不可以有其他的Exclusive/Update Lock存 在。它在真的要Update时会把Update Lock提升成Exclusive Lock,所以啦, 在它真的要Update前於其上的所有Lock(包括Share Lock)都要解除才能成功。 +----------------+---------------------------------------------------- | | 目前已有的Lock | |----------------+---------+-----------+------------+----------------| |想要完成之Lock | no lock | Share Lock| Update Lock| Exclusive Lock | |----------------|---------+-----------+------------+----------------| |share lock | 可 可 可 不可 | |update lock | 可 可 不可 不可 | |exclusive lock | 可 不可 不可 不可 | |----------------+---------------------------------------------------+ 以下我暂且用Row Lock来解释一些东西,读者可另外推及Page Lock。 一、SQL Server6.5的 rdConCurLock(悲观的锁定) 这个rdConCurLock会在它读过的Row上做一个Update Lock,那代表什麽?代表其他 的Process如果想读取rdConcurLock方式读过的资料,那没有问题,因为读取的动作顶多 是Share Lock甚而是没有Lock,方才提过,同一Record允许多个Share Lock於其上,所 以只是读取资料时没有问题。如果说Process A 以rdConcurLock方式的Cursor目前指向 ResultSet的第5笔资料,另外有一个Process B 使用乐观锁定的Cursor,且ResultSet成 员相同,而它正指向第1笔资料,Process B 想要来更新资料时会如何?答案是可能无法 更新,因为rdConcurLock已读过第1笔资料,所以在上面做了一个Update Lock,Process B 想Update它,前题是要先能Exclusive Lock该笔,但因其上已有Update Lock所以Lock不成 ,而Lock 不成的情况下会如何,那要看我们设定Lock时TimeOut的时间是多少,一次Lock 不成会自动再试着Lock,如果在TimeOut的时间内Lock成功便OK(那更新便可成功),否则就 会产生一个Error。而rdConCurLock的Update Lock何时才会Releas呢?可能是Close ResultSet 或Transaction结束等等。正因rdConCurLock会在其上放Update Lock,所以它不允许其他的 Process也在相同的Resultset上以rdConCurLock的方式开启。相反的,方才的例子中,如果 Process A回头想Update 第一笔资料时则会成功,因为乐观的锁定在读取到资料後,便会 Release Share Lock而变成没有Lock,这在乐观锁定中再详谈。 二、OpenLink的Informix ODBC Driver没有提供rdConcurLock的功能 就算我们以rdConcurLock的方式来OpenResultset,也不会有错,只是其行为是乐观 的锁定,除非,设定Isolation Level才会有Lock在上面,这容後再述。 三、SQL的乐观锁定 乐观锁定分成两种:rdConcurValues/ rdConcurRowVer,这二者的区别主要在於:确定 想修改的那个Row,在读取与想修改之间有没有被其他Process修改过的认知。如果是 rdConcurValues那代表使用的是各个栏位的值,而rdConcurRowVer则是利用Timestamp, TimeStamp是SQL Server自动维护的一个栏位,当某个Row有更新时,便会自动更新於其上 的TimeStamp栏位,所以我们Update时,SQL Server会用原始读出的TimeStamp值与目前的 TimeStamp值做一比较,如果不同代表先前已被别人Update了,因此rdConcurRowver比较有 效率。而Table中就要有timestamp的栏位才能使用rdConcurRowver,否则在OpenResult时 会产生一个Warnning。除此之外,这两种乐观锁定似乎没有太大不同。 乐观锁定很奇特,它在读取出资料时(如OpenResultSet)会产生Share Lock,而读取出 资料之後的所有Record含Current Record竟然没有做锁定(连Share Lock也没有),而且不管 我们的Cursor是否是Update Cursor都如此,只有在Update时才会去做Exclusive Lock。如 果,这个Update指令是under Transaction那这Exclusive Lock不会去除,等Transaction Committed/RollBack 时才Release。再来一个Case,如果Process A以乐观锁定的方式来 开启Resultset,Process B也以乐观的锁定开启相同的Resultset,而且二者同时皆指向同 一笔Record,Process A先行Update该笔,而後Process B再想Update时,会产生错误,如果 是以rdOpenKetset/rdOpenDynamic方式那Process B便得先rs.Move 0, rs.Edit重新修正 资料最後再rs.Update一次。请和先前一个Process是悲观锁定,一个是乐观锁定而Update 不同笔资料做一比较,为何之前的Update指令会等待Process A的Resultset 去除锁定, 而这个例子是什麽也不等,一下子就产生Error?(提示:这个例子中,Process A update 之後便Release Lock变成没有Lock),当然这个例子是没有Under Transaction时的记录, 反过来,如果Under Transaction呢,Process A先Update该Reocrd後未Commit/Rollback 前,在该笔(或其所在的Page)会有一个Exclusive Lock,此时如果Process B来Update时 则会进入等待,直到Procees A如果Commit Transaction则Process B的Update产生Error 或者Process A Rollback Transaction则Process B的Update可成功。 这和我原本的想像不同,我原本的想法,Server端的Cursor是由Declare Cursor/ Open Cursor/Fetch/Close Cursor等指令直接来做,但是我查一些书,得知如果是Update Cursor在Fetch到资料时,会在Current Record所在的Page上做Update Lock,如果不是Update Cursor则做Share Lock,而且其Lock会一直保存,直到下一个Fetch或Close Cursor或 Commit/Rollback Transaction等,而不是像现在只有读出的那一个时点会做Lock,读出後 便不Lock了。这中间的行为模式之不同,应是ODBC与Server端的Cursor间另有一个机制所造成 ,而我不知这中间的机制是什麽。 四、InforMix的乐观锁定 基本上,Informix的乐观锁定和SQL Server没有太大的不同,然而Informix提供Row Lock的功能,这是和SQL Server不同之处。 上面说明了ODBC乐观锁定和悲观锁定的行为模式,基本上,说明的是读取到资料之後,与 Updtae资料之後,使用何种Lock於Current Record或读取过的Record,而我上面的说明全 来自我的Testing,我分别使用SQL EnterPrise Manager与Informix Sysmaster Database 的syslocks Table来查寻Lock的情况。但这里还有一个重点没有说到,那就是什麽情况之 下才能顺利"读取到"资料;而上面的讨论是读取成功之後,有没有要在Object上做Lock。 这是Set Transaction Isolation Level的讨论范围。请查下一个Topic