转至繁体中文版     | 网站首页 | 图文教程 | 资源下载 | 站长博客 | 图片素材 | 武汉seo | 武汉网站优化 | 
最新公告:     敏韬网|教学资源学习资料永久免费分享站!  [mintao  2008年9月2日]        
您现在的位置: 学习笔记 >> 图文教程 >> 软件开发 >> VB.NET程序 >> 正文
ADO 的测试         ★★★★

ADO 的测试

作者:闵涛 文章来源:闵涛的学习笔记 点击数:1847 更新时间:2009/4/23 14:58:00
 DO Cursor/Lock/Concurrency 的测试 来源:cww
  我个人认为ADO2.0在这方面的表现实在是不好,我看ADO更高的版本会不会比较好一点。或许,要在SQL7.0之下才会有良好的表现,而我使用的是SQL 6.5与Informix。怎堋说呢?
注:我终於用有SQL7.0可以Testing了,而且Concurrency的表现不错哦,所以了,如果
您想用ADO而且是SQL Server当後端,那就使用Sql7,不要用SQL6.5

我们先看一下Recordset中CursorType的属性

AdOpenForwardOnly 顺向资料指标?
AdOpenKeyset 索引键集 (Keyset) 资料指标?
AdOpenDynamic 动态资料指标?可看到其他使用者所做的增加,变更和删除结果
AdOpenStatic 静态资料指标

  以上这一些和RDO的定义没有什堋不同, 然而我也在该篇文章中指出,这些要和Cursor所在的位置与RDBMS都有相关。

  RDO中Cursor的位置可分为rdUseODBC(对应ADO的AdUseClient),rdUseServer(对应ADO的AdUseServer),rdUseNone(ADO中没有直接的对应)。ADO Recordset的CursorLocation = AdUseClient时,只有AdOpenStatic/AdOpenForwardOnly的CursorType会有作用,其他的二者和AdOpenStatic有相同的效果。如果是AdUseServer呢,在SQL Server中上述的四种CursorType都可以用,但是RecordSet中的Resync方法只有
在adOpenKeyset的CursorType才能用,AdOpenStatic不能使用。而RDO中经常使用的rdUseNone的CursorType在ADO中没有相对应的设定,那该如何呢?
那得设定
rs.CursorLocation = AdUseServer
rs.CursorType = AdOpenForwardOnly
rs.LockType = AdLockReadOnly
rs.CacheSize = 1
  来取代RDO的rdUseNone,而且注意的是不可使用Client端的Cursor,否则RecordSet Open的时间会久(因为Client端的Cursor在ADO中都是Static的Cursor而不管我们如何设)。

  OpenLink ODBC Driver for Informix又有点不一样,如果使用Server端的Cursor,那只能设定是AdOpenForwardOnly的CursorType,否则会有意想不到的结果,而使用Client端的Cursor呢,只有AdOpenStatic/AdOpenForwardOnly二者有效,不过特别的是AdOpenStatic
在这里呢却可以使用Resync的方法,只要说我们的Table有Unique的Key且有Select进来,便可以用,因为下rs.Resync adAffectCurrent 在Informix 中是以另一个查询当笔资料的Query来做(如Select * from TableName Where KeyFl eyvalue),就因为要Query到当笔,所以一定要有Unique的Key,否则Resync会有错。

再来讨论一下Lock
RecordSet的LockType有以下的设定:

adLockReadOnly 预设值。唯读 -- 您无法变更资料。
adLockPessimistic 悲观性锁定,通常会在编辑时立即在资料来源锁定记录。
adLockOptimistic 乐观性锁定,在您呼叫 Update 方法时才锁定。
adLockBatchOptimistic 悲观性批次更新

  悲观性批次更新我不讨论,而唯读也够明显了,这都不讨论。基本上SQL6.5用OLEDB Provider来连时,只有乐观锁定,SQL7.0後才有悲观锁定。SQL6.5想要有悲观锁定,那就用ODBC Provider的方式来做吧!RDO悲观锁定基本上在Resultset建立时,便会自动Fetch第一笔,所以在该笔所在的Page上会有一个Update Lock。而ADO又不太相同,它在Recordset pen之後并不会自动Fetch第一笔,直到我们想引用它或Move系列指令下达时才会有作用。


  上面的Lock是针对Recordset,也就是以Page/Record为对像,如果想要做Table Exclusive Lock於SQL6.5 设定SQL指令如下:

Select * from qppfa (TabLockX) Where ....

  TabLockX代表会对该Table做Exclusive Lock,不过这种Lock对程式设计没有太多用处,因为这种方式的Lock会在Fetch时做Table Lock,一旦Update资料或Transactiont结束後会令该Lock Release掉,如果没有Transaction,那情况是:Fetch时做Table Lock,Update
後Release Lock,Fetch下一笔时再产生Table Lock,而不是们想像的会一直做Lock。

  而Informix的Table Lock则好多,它可以用Lock Table table-name in Exclusive Mode的指令来做,也就是说我们用Connection物件的Execute方法来执行上述的指令便可。

  在SQL Server6.5之下

  1.不像RDO2.0 有一个rdConcurLock的设定;虽然ADO有一个adLockPessimistic的LockType,如果透过OLEDB Provider来做,似乎全不是那一回事,怎堋用,都是乐观的锁定。除非使用ODBC Privder的方式,才会有悲观锁定。

  2.RDO 中如果ProgramA 与 ProgramB 同时指到某一笔Record,而後ProgramA成功的Update该笔资料且Commit,而ProgramB这时也随即Update该笔资料,这时ProgramB会收到一个错误讯息,这时只要下

Recordset.Move 0
Recordset.Edit
设定更改的值
Recordset.Update 便可以重新来做一次

但是ADO呢,我个人认为在Update之後产生错误时,正确的使用方式应是:
(rs as ADODB.Recordset)
rs.CancelUpdate
rs.Resync adAffectCurrent
set new value for recordset
rs.Update
  但实№上会在rs.Resync adAffectCurrent这一行再产生错误,而此时Recordset的内容却有Refresh成Remote资料库的实№资料内容,好奇怪!我不知道这里是我的做法有误,还是SQL Server 7.0才能如此,至少SQL Server6.5我失败了。以至於Update的程式要变成:

cn.BeginTrans
On Error Resume Next
rs!fld1 = "v"
rs.Update
Do While cn.Errors.Count $#@62; 0
If cn.Errors(cn.Errors.Count - 1).Number = -2147217887 Then
-2147217887 代表该Record可能被他人更新了 for Server端Cirsor
ans = MsgBox("资料更新有冲突,是否再试一次", vbYesNo)
If ans = vbYes Then
rs.CancelUpdate
rs.Resync adAffectCurrent 这里也会产生一个error
cn.Errors.Clear
rs!fld1 = "v"
rs.Update
Else
Exit Do
End If
Else
Exit Do
End If
Loop

If cn.Errors.Count = 0 Then
cn.CommitTrans
Else
cn.RollbackTrans
End If

  以上程式是rs.CursorLocation = adUseServer 的情况,而用rs.CursorLocation = adUseClient呢,情况又不太相同,基本上这是不提供rs.Resync方法。这种程式能看吗?实在不好吧?所以在这里我的建议是,使用OLEDB Provider来连SQL6.5时,最好是同一笔资料同时间被Update的机率很小,如果发生了,就只好Requery,再想办法指到该笔,再重新Update,要不就要用上面的方式,再不就产生错误,要使用者再重新执行一次。只要同时Update的可能性小,可能好几年都不会遇上同时Update的问题。

  我们知道在实№的应用上有不少是有可能同时Update同一资料的,例如说,我们用一笔Record来记录流水号,每个Process要取得该Record流水号的那个栏位之内容,之後加1再存回去,这种情况在多人使用时就很有可能有同时Update的情况,那我建议使用ODBC
Provider的悲观锁定,不过,仍有些问题,如果以下程式所示,而有两个Process A,BA执行到rs.MoveFirst後换 B执行到rs.MoveFirst,此时有Dead Lock产生,所以B 会进入等待,而A 呢,它执行到Update时会产生错误,天!这种程式能用吗?所幸,SQL7不会有回题。

Private cn As ADODB.Connection
Private rs As ADODB.Recordset


Dim connstr As String
Dim ans As Integer, errstr As String, sql As String
Set cn = New ADODB.Connection
connstr = "Driver={SQL Server};UID=cww;PWD=jjh5612;Server=OPEN_VIEW;Database=cwwtest"
cn.Provider = "MSDASQL"
cn.ConnectionString = connstr

cn.Open
cn.BeginTrans
sql = "Select * from qppfa where case_no = E8701761 and seq BETWEEN 1 AND 5 "
Set rs = New ADODB.Recordset
Set rs.ActiveConnection = cn
rs.CursorLocation = adUseServer
rs.Source = sql
rs.Open , cn, adOpenKeyset, adLockPessimistic, adCmdText
rs.MoveFirst 这时候才真的有Update Lock
rs!kind = "v"
rs.Update
cn.CommitTrans
$#@60;/pre$#@62;$#@60;/td$#@62;$#@60;/tr$#@62;$#@60;/table$#@62;在Informix之下(用OpenLink的ODBC Driver)呢,情况很乱,後来我发现只要使用Client
端的Cursor,问题会减到最少,而且这里有一点十分奇特,OpenLink ODBC Driver允许
我们使用Recordset的Resync方法,不但没有错,而且还会把on-line Database的资料
传回来(这一点和使用RDO 的Client端Cursor不同,和 ADO SQL Server6.5也不同)。
不过这里要特别提出的是Resync adAffectCurrent 只在我们的Table有Unique的Key,
而且这个Key有在我们的Select的范围内才有效。所以,以下是我OpenLink ODBC Driver
解决Update concurrency的方式。特别提出是,在这OpenLink ODBC Driver下使用ADO,
千万不要用Server端的Cursor,会有太多问题(除非是AdOpenForwardOnly)。以下的程式
只可用於OpenLink Informix ODBC Driver,不可用於SQL Server!!

$#@60;table border$#@62;$#@60;td$#@62;$#@60;tr$#@62;$#@60;pre$#@62;

Dim WithEvents cn As ADODB.Connection
Private WithEvents rs As ADODB.Recordset
Private qry As ADODB.Command
Private adoerr As ADODB.Errors

以下是 update资料库的部份
Private Sub UpdateData()
Dim ans As Integer
cn.Execute "Set lock mode to wait 15" 该设定只对Informix有效
cn.BeginTrans
rs.MoveNext
On Error GoTo errh 设定Update 的错误处理函式
updArea: 设定这一个标记,方便错误函式返回这里做事情

rs!fld1 = "h" 自行更改成update所 的设定
rs.Update 如果Update时产生错误时,则会到errh处处理
cn.CommitTrans
Exit Sub

errh:
Do While cn.Errors.Count $#@62; 0
If cn.Errors(cn.Errors.Count - 1).Number = -2147217864 Then
-2147217864 代表该Record可能被他人更新了 for Client端Cirsor
ans = MsgBox("资料更新有冲突,是否再试一次", vbYesNo)
If ans = vbYes Then
rs.CancelUpdate
rs.Resync adAffectCurrent 重新到Database读取当笔资料
cn.Errors.Clear
Resume updArea 重回资料更新的区域
Else
Exit Do
End If
Else
Exit Do
End If
Loop
MsgBox "Update失败" + vbCrLf + cn.Errors(0).Description, vbCritical
cn.RollbackTrans
End If
End Sub

开启资料库
Private Sub Form_Load()
Dim connstr As String
Dim ans As Integer, errstr As String, sql As String
Set cn = New ADODB.Connection
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.ConnectionString = connstr
cn.Open
sql = "Select * from testtab order by case_no"
Set rs = New ADODB.Recordset
Set rs.ActiveConnection = cn
rs.CursorLocation = adUseClient
rs.Open sql, cn, adOpenKeyset, adLockOptimistic
End Sub


SQL7.0呢,这就很好用了,不管乐观锁定或悲观锁定都有很好的表现,我们先看悲观锁定:
Private Sub Form_Load()
Dim connstr As String
Dim sql As String
Set cn = New ADODB.Connection

connstr = "Data Source=ACCOUNT;UID=sa;PWD=;Initial Catalog=NKIUAcc"
cn.Provider = "SQLOLEDB"
cn.ConnectionString = connstr
cn.Open
cn.BeginTrans
sql = "Select * from TESTTAB"
Set rs = New ADODB.Recordset
Set rs.ActiveConnection = cn
rs.CursorLocation = adUseServer
rs.Source = sql
rs.Open , cn, adOpenKeyset, adLockPessimistic, adCmdText
rs.MoveFirst
rs!f1 = "x"
rs.Update
cn.CommitTrans

  这样做,如果同时有两个Process执行完rs.Open,而接著都会执行rs.MoveFirst,这时只有一个Process会成功,另一个则会进入等待,等到先前的Process Release Lock後才会再执行,这样子就解决了同时Update一笔资料的问题。唯一要注意的只有等待的时间若太久则会TimeOut,所以改成以下的方式:

Dim cn As ADODB.Connection
Private rs As ADODB.Recordset
Private Sub Form_Load()
Dim connstr As String
Dim sql As String
Set cn = New ADODB.Connection

connstr = "Data Source=ACCOUNT;UID=sa;PWD=;Initial Catalog=NKIUAcc"
cn.Provider = "SQLOLEDB"
cn.ConnectionString = connstr
cn.Open
sql = "Select * from TESTTAB"
Set rs = adoOpenRecordset(cn, sql, atServer, 悲观)
cn.BeginTrans
If rs Is Nothing Then
cn.RollbackTrans
Else
rs!f1 = "q"
rs.Update
cn.CommitTrans
End If

以下在.Bas
Public Enum adCursorLoc
atClient = 0
atServer
End Enum
Public Enum adLockType
唯读且向前 = 0
悲观
乐观
唯读
End Enum
Public Function adoOpenRecordset(Conn As adodb.Connection, Source, _
Optional CursorLoc As adCursorLoc, Optional LockType As adLockType) As adodb.Recordset
Dim rs As adodb.Recordset
Dim tryTimes As Integer
Dim vv As Variant
Set rs = New adodb.Recordset
If LockType = 唯读且向前 Or LockType = 悲观 Then
CursorLoc = atServer
rs.CacheSize = 1
End If
If CursorLoc = atClient Then
LockType = 乐观
End If
If CursorLoc = atServer Then
rs.CursorLocation = adUseServer
Select Case LockType
Case 唯读, 唯读且向前
rs.LockType = adLockReadOnly
Case 悲观
rs.LockType = adLockPessimistic
Case 乐观
rs.LockType = adLockOptimistic
End Select
Else
rs.CursorLocation = adUseClient
rs.LockType = adLockOptimistic
End If
Err.Clear
On Error GoTo errh
If TypeOf Source Is adodb.Command Then
rs.Op

[1] [2]  下一页


[VB.NET程序]ADO 在informix的 Addnew  [VB.NET程序]ADO 揭密 1
[Web开发][ADO]如何修改ADO的线程模型  [Web开发]Delphi7下仿Ado.Net类的实现
[Web开发]通过COM使用ADO  [Web开发]ADO & ADO.NET中使用存储过程的两个共用的函数
[Web开发]Binding a DataGrid to an ADO Recordset  [Web开发]ADOCE for ADO Programmers
[Web开发]Delphi多线程下的ADO编程  [Web开发]在delphi.net的VCL.net里使用Ado.net
教程录入:mintao    责任编辑:mintao 
  • 上一篇教程:

  • 下一篇教程:
  • 【字体: 】【发表评论】【加入收藏】【告诉好友】【打印此文】【关闭窗口
      注:本站部分文章源于互联网,版权归原作者所有!如有侵权,请原作者与本站联系,本站将立即删除! 本站文章除特别注明外均可转载,但需注明出处! [MinTao学以致用网]
      网友评论:(只显示最新10条。评论内容只代表网友观点,与本站立场无关!)

    同类栏目
    · C语言系列  · VB.NET程序
    · JAVA开发  · Delphi程序
    · 脚本语言
    更多内容
    热门推荐 更多内容
  • 没有教程
  • 赞助链接
    更多内容
    闵涛博文 更多关于武汉SEO的内容
    500 - 内部服务器错误。

    500 - 内部服务器错误。

    您查找的资源存在问题,因而无法显示。

    | 设为首页 |加入收藏 | 联系站长 | 友情链接 | 版权申明 | 广告服务
    MinTao学以致用网

    Copyright @ 2007-2012 敏韬网(敏而好学,文韬武略--MinTao.Net)(学习笔记) Inc All Rights Reserved.
    闵涛 投放广告、内容合作请Q我! E_mail:admin@mintao.net(欢迎提供学习资源)

    站长:MinTao ICP备案号:鄂ICP备11006601号-18

    闵涛站盟:医药大全-武穴网A打造BCD……
    咸宁网络警察报警平台