Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1756091
  • 博文数量: 600
  • 博客积分: 10581
  • 博客等级: 上将
  • 技术积分: 6205
  • 用 户 组: 普通用户
  • 注册时间: 2008-11-06 10:13
文章分类
文章存档

2016年(2)

2015年(9)

2014年(8)

2013年(5)

2012年(8)

2011年(36)

2010年(34)

2009年(451)

2008年(47)

分类:

2009-10-11 11:17:55

来源:cww
上回谈的是如何建立连结,这SQL与Informix没有什麽不同,但是
再来要谈的是令人十分痛苦的事了,那便是如何产生一个rdoResultSet物件
rdoResultSet相对应於DAO的Recordset物件,产生的方式主要如下:
Private WithEvents cn   As rdoConnection
Private en As rdoEnvironment
Private rs As rdoResultset
Private qry As rdoQuery
Dim sql As String 

Set en = rdoEnvironments(0)
Set cn = New rdoConnection

en.CursorDriver = rdUseServer  '见注一
connstr = "UID=cww;PWD=jjh5612;Database=cwwpf@eis;" _
        + "Driver={OpenLink Generic 32 Bit Driver};" _
        + "Host=192.168.0.61;" _
        + ";FetchBufferSize=30" _
        + ";NoLoginBox=Yes" _
        + ";Options=" _
        + ";Protocol=TCP/IP" _
        + ";ReadOnly=No" _
        + ";ServerOptions=" _
        + ";ServerType=Informix 7.2"
cn.Connect = connstr
Set cn = en.OpenConnection("", rdDriverNoPrompt, _
                           False, connstr)   '第三个叁数False表示非ReadOnly
.
.
rs.Close
cn.Close
如果不想cn 加入en.Connections之中,则改用以下方式
Set en = rdoEnvironments(0)
Set cn = New rdoConnection
connstr = "UID=cww;PWD=jjh5612;Database=cwwpf@eis;" _
        + "Driver={OpenLink Generic 32 Bit Driver};" _
        + "Host=192.168.0.61;" _
        + ";FetchBufferSize=30" _
        + ";NoLoginBox=Yes" _
        + ";Options=" _
        + ";Protocol=TCP/IP" _
        + ";ReadOnly=No" _
        + ";ServerOptions=" _
        + ";ServerType=Informix 7.2"
Set cn = New rdoConnection
cn.CursorDriver = rdUseServer
cn.EstablishConnection rdDriverNoPrompt, False
sql = "Select * From qppfa"
Set rs = cn.OpenResultset(sql, rdOpenForwardOnly, _
    rdConcurReadOnly)
.
.
rs.Close
cn.Close
重点都是在OpenResultset这个方法上,但是如果要做更多的控制,我会在rdoQuery上使
用OpenResultset,如下:
Set en = rdoEnvironments(0)
Set cn = New rdoConnection

cn.CursorDriver = rdUseServer
connstr = "UID=cww;PWD=jjh5612;Database=cwwpf@eis;" _
        + "Driver={OpenLink Generic 32 Bit Driver};" _
        + "Host=192.168.0.61;" _
        + ";FetchBufferSize=30" _
        + ";NoLoginBox=Yes" _
        + ";Options=" _
        + ";Protocol=TCP/IP" _
        + ";ReadOnly=No" _
        + ";ServerOptions=" _
        + ";ServerType=Informix 7.2"
cn.Connect = connstr
cn.EstablishConnection rdDriverNoPrompt, False
sql = "Select * From testtab"

Set qry = cn.CreateQuery("MyQuery", sql)
qry.RowsetSize = 50   '见注二
qry.MaxRows = 200     '见注三 
Set rs = qry.OpenResultset(rdOpenKeyset, _
        rdConcurRowVer)
.
.
rs.Close
cn.Close
至於说OpenResultset方法中又提及记录集又分成以下四种:

rdOpenForwardOnly 0  (预设值)是固定集 (Fixed Set),不可卷动 (Non-Scrolling)
rdOpenKeyset      1   固定集,可卷动的查询记录集的资料指标,存的只是Key,而其
                      他的资料於需要时可以去读取,因此它可以读到其他人更新过後
                      的资料,当然,需和RowSetSize做搭配,别人在我们读取到Data
                      後才更新资料时,我们的Process仍然没有反映最新的资料,此
                      时下个Move 0指令可以更新至最新的Data。不过看不到其他人新
                      增到该Result Set的资料
                     
rdOpenDynamic     2   动态集的资料指标,特性和rdOpenKeyset同,唯其他Process加入
                      该Resultset的资料可以在目前Process中看到。
rdOpenStatic      3   是固定集,和rdOpenKeyset不同的是,资料集一建立之後就看不
                      见其他Process对Resultset的修正。

其实,我觉得MS 对於这些东西的说明十分不清楚,而且上面的说明针对的都是rdUseServer
的Server端之Cursor,而ODBC端的Cursor没有像上面所说的那样,ODBC端的Cursor因为
资料是Copy到Client端,自然也就看不到他人是如何对Resultset成员的修改了;当然了,
理论上还是可以得知,不过这要花上代价,那就是每一次读取资料时还得向Server来询问
是否有改,那不就失去Client端Cursor的原意了吗?所以我们可以想像,ODBC端的Cursor
只有rdOpenForwardOnly与rdOpenStatic这两种。

这样就结束了吗?还没有!以上是MS SQL SERVER6.5的特性,而Informix呢?InforMix
Server端的Cursor只有rdOpenForwardOnly与rdOpenKeyset两种(注意,不是rdOpenStatic)
这和Informix Server有关,然而我们在Informix为後端的Server中使用rdOpenStatic/
rdOpenDynamic时,也不会有误,只是行为和rdOpenKeyset相同。而Informix为後端,但
我们使用rdUseOdbc之Client端Cursor呢,此时只有rdOpenForwardonly与rdOpenStatic
(注意,不是rdOpenKetset喔),这个原因是来自於ODBC Cursor的特性。

而不管是SQL SERVER或Informix为後端,rdUseNone的方式就没有太多的选择,一律只能
使用rdOpenForwardonly的Cursor型态,这不必多说,应是很自然的事吧。

透过上面的说明,何时用Client端的Cursor何时用Server端的Cursor应比较有念了吧。

注一:
CursorDriver 有以下数种方式 rdUseIfNeeded 0 ODBC 驱动程序 将选取适当的资料指标样式。可能的话,使用 伺服端资料指标。 rdUseOdbc 1 将使用ODBC 资料指标程序库(ODBC Cursor Library)。 rdUseServer 2 使用伺服端资料指标。 rdUseClientBatch 3 RDO 将使用乐观批次资料指标程序库 rdUseNone 4 记录集(Result Set)不以资料指标型态传回。 而这里想讨论的是 rdUseOdbc rdUseServer rdUseNone,而rdUseClientBatch不多做讨论 rdUseOdbc 在Client端建立Cursor来管理Cursor的移动,因为是在Client端,所以实作 上是在Client端Copy一份ResultSet,不同的Client端各自有其一份资料; 假设有A,B两个Client端要求了相同的资料,如:都是下Select * from testtab 之SQL指令,假设一共有740笔资料,那麽,A, B各自保有740笔资料,如果 对这些资料作更动,A看不见B,B也看不见A(这合理嘛,因为各自有其资料 的Copy )。然而这740笔资料是在什麽时候传到Client端呢?并不是OpenResultSet 时便立即全部传过来,而是一开始只传部份的资料过来,而Cursor指到後面 的资料时,才会将之再传过来。所以,如果我们使用MoveLast方法时,会看到 这个指令执行时整个程序停顿了下来(没有使用非同步传送时),这时候电脑 便是在接收Server端传送来的资料,如果我们在传送资料的过程中查看一下硬 碟空间,会发现,空间正被用走,而且传送的过程时而会停个一下下。而这 rdUseOdbc的Cursor在Server端有没有做什麽动作呢?这个没有书有做说明,而 我认为Server端可能也会产生一个ForwardOnly的Cursor或者一个Tmp 的Table, 否则Server如何知道曾传过了多少资料给Cilent端是不是呢?(先前提过,并 不是在OpenResultset时便把所有资料传过来,而且在OpenResultSet时,会花 个一些时间才完成,时间的多少要看资料量与Sql的语法)。为什麽我会如此假设 呢,我做过一些Testing,如果Cursor的建立很容易,例如:Select * from testtab where id between 1 and 800 (而有在id上做Index),那麽,这个Cursor的 建立很快,一下子便可以传回Client端了;我们可以想像,这种Cursor我们可以 在Server端建一个ForwardOnly的Cursor,所以只要Fetch个某个数量的资料後, 便可传回Client了,所以速度快,等需要更多资料时便从目前Server端的Cursor 位置再继续读取下去。相反的,如果是Select * From testtab where fld2 = 'tt' order by fld3 (fld2, fld3上没有Index),这时候,就得在tmp Database中建立起该Table了,要不就得将所有Table中的Data都传到Client了, 我想,应是在Tmp Database中建Table比较像,所以这一类的Cursor在建立时 就要花较多的时间,相对的OpenResultSet的时间就会久。 rdUseServer 和rdUseODBC相反,Cursor是在Server端建立,在Server端所建的Cursor和资料 库的特性就习习相关,我们如果查阅RDO的使用说明,会告诉我们Cursor又有分 Static, Keyset, Dynamic, ForwardOnly等等,但并不是所有的Database Server 都具有这个能力,例如说,SQL Server中就有所谓的Dynamic Cursor,这种 Cursor的特色在於:我们的Resultset建立完之後,别人新增了资料,只要该 资料在我们ResultSet的范围,我们也可以看得到它。然而,这种Dynamic的Cursor 在Informix 是没有提供的;但是一般来说,发展ODBC的厂商并不会在我们使 用Server 端没有提供的Cursor种类时,产生任何错误,取而代之的是,他们 会使用另一种较接近的Cursor来取代,例如说,对Informix Server使用Dynamic Cursor时,并没有产生错误,而其dynamic Cursor的行为和KetSet Cursor相同( 例:如果我们Server端是SQL Server,那使用Dynamic Cursor的Resultset,其 RowCount会传回-1 ,但如果Server端是Informix则传回实际的笔数)。使用 Server端的Cursor有好处也有坏处,好处等一下再说,先讲它的坏处,因为 Cursor要由Server来handle,所以多人使用时很浪费资源,尤其使用的Cursor 如果具有任意往前往後移动者(这叫Scroll Cursor),会在Server端的Temp database建立table,那花的时间与Resource会较多。rdUseServer所建的Cursor 如果是属於Scroll Cursor者(static, keyset, dynamic皆是)它会在Server端 将资料全准备好才算完成我们所下的OpenResultset的方法,如果资料量又大的话 ,那这个temp的table就会很大,可能会使我们的Resultset会造不出来。一般来 说,使用rdUseServer的Scroll Cursor在OpenResultset时花的时间会比rdUseODBC 的Scroll Cursor多,但是使用MoveLast时,刚好相反,因为Server端的Scroll cursor是使用Temp Database中所建立的Temp table,而这table在OpenResultset 时,便已完全的造出了。当然了,不管用Server/Client端的ForwardOnly Cursor (即OpenResultset使用rdOpenForwardOnly叁数),在OpenResultset时花的时间都 比较少,因为不必在Server端建立temp table;而的Cursor建立起来的速度(即 OpenResultset的速度)除了和是否是Scroll Cursor有关外,和所下的Sql指令与 RowSetSize这个属性有关。 rdUseNone 字面上没有使用Cursor,不过我觉得在RDBMS中应仍旧是使用Server端的Cursor来 做,只是这种Cursor是ForwardOnly, ReadOnly,这类的Cursor不像Scroll Cursor 一定会在tmp Database中建立Table,所以Resource用得少,OpenResultset回应得 较快(建立快,且只Fetch一笔);因为OpenResultset方法会令Server端的Cursor 於Open Cursor後Fetch一笔资料,所以OpenResultset的速度快或慢,便取快於这 Fetch的速度了。而Client端呢,就真的没有Create Cursor来维护了。rdUseNone 的方式於只查寻没有修改、新增的情况中应是使用最多的一种,因它花费Server/ Client 的资源最少。使用它时,OpenResultSet只能使用rdOpenForwardOnly与 rdConcurReadOnly的搭配,不能使用其他搭配,而且其RowSetSize自动设成 1。 注:以上皆是本人的试验与假设,若有问题敬请多多指正。 而如何设定Cursor是在Client端或Server端呢,那便得设定CursorDriver。 如果没有设定,会使用内定的rdUseIfNeeded,而手动的设定要如此: 1.如果在rdoConnection上设定CursorDriver属性,便得使用EstablishConnection方法 来做,如下: cn.CursorDriver = rdUseServer cn.EstablishConnection rdDriverNoPrompt, False sql = "Select * From qppfa" Set rs = cn.OpenResultset(sql, ....) 2.如果在rdoEnvironment上设定CursorDriver属性,便得使用OpenConnection方法 来做,如下: en.CursorDriver = rdUseServer Set cn = en.OpenConnection("", rdDriverNoPrompt, False, connstr) sql = "Select * From qppfa" Set rs = cn.OpenResultset(sql, ....)
注二:
RowSetSize 是rdoQuery的一个属性,以下这一段是OnLine Help的说明 RowsetSize 属性确定有多少笔索引键集 (Keyset) 的资料列被应用程序放入缓冲区中。 RDO 使用RowsetSize 属性来确定有多少资料列被 ODBC 的 SQLExtendedFetch 函数读取 到记忆体中。调整 RowsetSize 之大小,会影响到其性能以及为维护索引键集缓冲区所 需的记忆体。 如何,是不是每个字都懂,但是就是有看没有懂,说实在的,我也不敢说全懂,不过我做 了一些Testing,这好像是: 1.如果是rdUseODBC的Cursor,这影响ResultSet一次传回Client端的笔数,例如: ResultSet中一共有800笔资料,在OpenResultSet时(且不为rdOpenForwardOnly)时, 不会将这800笔Data一次传回,而是先传回RowSetSize所设定的笔数(如:100);等要读 第101笔时会再要求Server把101-200笔的资料传回来。所以了,如果Cursor的需Scan table才能知道有哪些Row符合条件时,RowSetSize也会影响OpenResultset所需的时间。 2.如果是Server端的Cursor(rdUseServer),截录online help的说明 另外,当使用悲观锁定的 (rdConcurLock) 平行处理 (Pessimistic Concurrency) 时 ,RowsetSize 属性决定了有多少资料列(及其资料页)被锁定。例如,如果设定 RowsetSize 属性为 100 并且执行一个带有 rdConcurLock 选项的 rdoQuery 物件时 ,就锁定记录集的前 100 笔资料列以及和每一笔被锁定资料列相关的资料页,直到该资 料指标被关闭或将目前资料列指标移至该记录集的结束位置。在任何情况下,至少有 RowsetSize 笔资料列被锁定。 除此之外,RowSetSize也会影响Cursor建立後的一些特性,例如说,RowSetSize设为2 那代表OpenResultSet之後会读取两笔的资料,而此时的Current Record是第一笔,如果 尚未MoveNext到第二笔, 而第二笔资料被他人修改了(如果没有Tranaction而且是 rdOpenKeyset的ResultSet),那我们第一次下MoveNext後 (即指到第二笔资料),得到的 资料是未修改之前的Data,此时如果下Move 0的指令才会再得到最新的资料。相反的,如 果我们设RowSetSize = 1,而Cursor未指向第二笔前(即未MoveNext),第二笔资料被更 新了,而後的MoveNext会得到的是新的资料。 3.rdUseNone则固定RowSetSize = 1
注三:
MaxRows的设定限制了ResultSet的最多笔数,但Informix的设定没有效
阅读(753) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~