VB6基本数据库应用(十):【增补篇】游标Cursor和锁Lock简介

VB6基本数据库应用(十):【增补篇】游标Cursor和锁Lock简介,第1张

概述同系列的第十篇,上一篇在http://blog.csdn.net/jiluoxingren/article/details/48606399 【增补篇】游标Cursor和锁Lock简介 说起来,我自己对游标并不怎么了解。这里简单就我所知道的做一些介绍。之所以要说一下,是因为趁着出增补篇的机会,将游标和锁也要提及一下,尽管这在VB中的重要性并不明显,但是游标的功能你每一次读写都在用,锁在背后影响着你

同系列的第十篇,上一篇在http://blog.csdn.net/jiluoxingren/article/details/48606399

【增补篇】游标Cursor和锁Lock简介

说起来,我自己对游标并不怎么了解。这里简单就我所知道的做一些介绍。之所以要说一下,是因为趁着出增补篇的机会,将游标和锁也要提及一下,尽管这在VB中的重要性并不明显,但是游标的功能你每一次读写都在用,锁在背后影响着你的 *** 作。这篇增补篇也是为了修正以前代码上的错误,虽然看不到影响,那是数据库引擎在背后修正的结果。

游标

在RecordSet对象的Open方法中,第三,四个参数就是游标和锁。如下图所示


关系数据库中的 *** 作会对整个记录集起作用。例如,由sql:Select语句返回的记录集包括满足条件的所有记录。应用程序并不总能将整个记录集作为一个单元来有效地处理。这些应用程序需要一种机制以便每次处理一条记录或一部分记录。游标就是提供了这种机制。

在VB中的 *** 作是一个典型的例子,之前用ListBox来显示的时候,我们需要用循环逐条记录进行提取和显示。而且,MoveNext,MovePrevIoUs等移动 *** 作都是由游标提供的。

按照游标的支持类型,可以分为Transact-sql游标,API游标,客户游标。

1. Transact-sql游标:由T-sql的DECLARE CURSOR语句定义,主要用在服务器。

2. API游标:支持在olE DB,ODBC等,主要用在服务器上。客户端调用API游标函数,本地引擎会将这些请求传送到服务器(不一定是联机服务器,这里的服务器甚至可能指的是自己的电脑,由本地的数据库引擎负责这些功能)进行处理。

3. 客户游标:主要在客户机上缓存结果集时才用的。

前两者因为一般用在服务器上,故称服务器游标。而Recordset默认使用服务器游标。VB中,Recordset对象的CursorLocation属性可以设置使用服务器游标(adUseServer)还是客户游标(adUseClIEnt)。客户游标的功能一般比服务器游标弱。

按照游标的特性,游标有四种,分别是:静态游标,动态游标,只进游标,键集游标。这四种游标实现的效果各不相同。

1. 静态游标:对应VB的adOpenStatic常量。静态游标将查询的结果记录集生成一个快照,所以别人对原始数据的增删改都不会对我已经读出来的结果有影响。静态游标的数据是只读的,不能做其他的任何 *** 作。


2. 动态游标:对应VB的adOpenDynamic常量。动态游标是消耗资源最大的。但是别人对原始数据的增删改都能表现出来,当然自己的 *** 作肯定也是可以表现出来的。


3. 只进游标:对应VB的adOpenForwardOnly常量。这是最省资源的游标。但是他只读的,而且只能往下一条记录读,如果想倒回去,那是不支持的。所以调用MovePrevIoUs方法将会失败。


4. 键集游标:对应VB的dOpenKeyset常量。这种游标介于动态与静态之间。你无法看到别人增加的数据;如果别人删除了数据,你访问被删除的数据就会出错;如果别人修改了数据,你将能够看到更改


能不能看到增删改的结果,是对于别人做的增删改而言的。如果游标支持增删改,那么自己通过游标所做的所有变动都可以看到。在VB上通过recordset对象进行的增删改,相当于是自己通过游标进行 *** 作,所以在update之后,用MoveLast就能读到新的数据。

另外,VB中还有一个用于说明不指定特定的游标的常量adOpenUnspecifIEd,让数据库引擎自己去选。

既然静态游标是只读的,那么为什么adOpenStatic,adLockOptimistic的搭配却能够增删改呢?


这里我特别说明了是adOpenStatic,adLockOptimistic的搭配。adLockOptimistic是锁的选项。锁的选项与数据能否被修改密切相关。

但是游标的设置与锁的设置并不一定能够兼容,这种情况下数据库引擎并不会报错,而是会主动选择一种合适的游标。也就是说,锁的设置会影响游标的设置(仅仅在ADO中是这样,其他地方不清楚)。而之前说的adOpenStatic,adLockOptimistic的搭配正是不兼容的搭配之一。

在说完锁之后,相信大家就能理解为什么是不兼容的了。而至于在这种搭配下,数据库引擎到底选择了那种游标。在第三部分【锁与游标搭配】中在说。

在并发 *** 作中经常会出现如下的问题:A读取数据Data,B也读取了数据Data。A修改并提交了,B随后也修改数据提交了。最终数据只保留了B的结果,A的结果丢失了。而我们需要的结果可能是:A修改之后,B更新数据,然后再根据当前的情况做修改。注意A,B可能并不知道彼此的存在,也不可能事先知道彼此的先后关系,他们的关系只有数据库管理系统(DBMS)知道。

锁是为并发 *** 作而生的。数据库的一大特性就是高度的数据共享。为了避免上述的情况(实际上并发 *** 作还会引起其他的问题),引入了锁机制。引入锁机制之后是这样的:A读取数据Data,并宣布我要修改数据。B只是晚了点,不过DBMS已经因为A而锁定了数据,B先等等吧。


锁也有很多种,ADO中不是提供你选择使用什么锁,而是让你选择锁的工作方式。锁工作的方式有以下4种:

常数(VB)

锁的工作方式

adLockReadonly

默认值,只读。无法更改数据。

adLock@R_239_3270@

保守式记录锁定(逐条)。提供者执行必要的 *** 作确保成功编辑记录,通常采用编辑时立即锁定数据源的记录的方式。

adLockOptimistic

开放式记录锁定(逐条)。提供者使用开放式锁定,只在调用 Update 方法时锁定记录。

adLockBatchOptimistic

开放式批更新。用于与立即更新模式相反的批更新模式。

adLock@R_239_3270@和adLockOptimistic的不同在于锁定的时机不同。前者保守,以防万一,从事务开始就锁定数据。后者开放,我改我的,只要我还没提交(Update),你随便弄。而他们两者都是以一条语句为单位的。

adLockBatchOptimistic与上面两者不同的是以批(多条语句的集合)为单位进行提交,一个批是一个整体。

锁与游标搭配

如果锁的工作方式与指定的游标不兼容,数据库引擎会改变游标。于是,在Open方法中提供的游标和锁就会有不同的搭配,这些不同的搭配中有不少都是不兼容的。下面列出所有的服务器游标(adUseServer搭配,以及对应的Jet数据库引擎实际采用的游标类型:

设定的游标

设定的锁

实际使用的游标

adOpenUnspecifIEd

adLockReadonly

adOpenForwardOnly

adLock@R_239_3270@

adOpenKeyset

adLockOptimistic

adLockBatchOptimistic

adOpenForwardOnly

adLockReadonly

adOpenForwardOnly

adLock@R_239_3270@

adOpenKeyset

adLockOptimistic

adLockBatchOptimistic

adOpenKeyset

adLockReadonly

adOpenKeyset

adLock@R_239_3270@

adLockOptimistic

adLockBatchOptimistic

adOpenDynamic

adLockReadonly

adOpenStatic

adLock@R_239_3270@

adOpenKeyset

adLockOptimistic

adLockBatchOptimistic

adOpenStatic

adLockReadonly

adOpenStatic

adLock@R_239_3270@

adOpenKeyset

adLockOptimistic

adLockBatchOptimistic

这个表是通过代码试验出来的,代码见最后附录。由这个表可知,Jet数据库引擎并不支持动态游标,它与任何一个锁方式搭配都不会使Jet数据库引擎使用动态游标。

而adOpenStatic与adLockOptimistic的组合也是不兼容的,最终Jet数据库引擎选择了adOpenKeyset(键集)游标。而键集游标是可以修改的。

以上都是服务器游标的效果,如果修改CursorLocation属性为adUseClIEnt,那么无论怎么搭配,结果使用的都是键集游标。

最后强调一点,前面几段开始,一直强调这是Jet数据库引擎的行为,并不是所有引擎都是如此!!!

不同游标的效果

前面介绍的四种游标,在上一节已经确定了一种——动态游标是不被Jet数据库引擎所支持的。这并不难理解,不止这个引擎不支持,还有别的一些引擎也不支持,因为这种游标太过强大,但是其缺点也非常明显。

另外的三种,可以发现键集游标(adOpenKeyset)是应用得最为广泛的。而adOpenStatic与adLockOptimistic的组合,实际上使用的也是键集游标。所以以后recordset的Open语句都改为使用键集游标和开放式的锁。如下语句所示:

VB代码开始:

' adOpenKeyset(键集游标),adLockOptimistic(开放式锁)

rs.Open "select * from Student",cn,adOpenKeyset,adLockOptimistic

VB代码结束

尽管之前我们并没有直接使用键集游标,但是由于数据库引擎的主动修正,我们认为自己用的是静态游标adOpenStatic,实际上用的是键集游标。键集游标的性质:可以反映自己所做的增删改,可以反映别人所做的修改。自己的增删改已经毋庸置疑,也不需要演示了,参见第四章即可,用recordset对象的属性进行增删改本质就是借助了游标。

然后我们来看一下,键集游标反映别人做的修改的能力。基本思路是这样。建立两个recordset对象,执行一样的查询。然后用一个recordset对象对一条记录进行更改;另一个对象重新输出自己的数据,观察结果。界面如下:


Text1用于输入StudentID,Text2用于输入Studentname。修改的时候只用到Text2,而且为了方便定第一条记录为被修改的记录。新增的时候两个文本框都要填。

VB代码开始:

Dim Cnn As New ADODB.Connection

Dim rec1 As New ADODB.Recordset

Dim rec2 As New ADODB.Recordset

'rec1修改第一个人的名字

Private Sub Command1_Click()

'移动回开头

rec1.MoveFirst

rec1.FIElds("Studentname").Value = Text2.Text'修改第一条记录的名字

rec1.Update

'清空List1重新填充数据

rec1.MoveFirst

List1.Clear

Do Until rec1.EOF

List1.AddItem rec1.FIElds("Studentname").Value

rec1.MoveNext

Loop

'清空List2重新填充数据

rec2.MoveFirst

List2.Clear

Do Until rec2.EOF

List2.AddItem rec2.FIElds("Studentname").Value

rec2.MoveNext

Loop

End Sub

'rec1新增记录

Private Sub Command2_Click()

'新增一个人的信息

rec1.AddNew

rec1.FIElds("StudentID").Value = Text1.Text

rec1.FIElds("Studentname").Value = Text2.Text

rec1.Update

'清空List1重新填充

rec1.MoveFirst

List1.Clear

Do Until rec1.EOF

List1.AddItem rec1.FIElds("Studentname").Value

rec1.MoveNext

Loop

'清空List2重新填充

rec2.MoveFirst

List2.Clear

Do Until rec2.EOF

List2.AddItem rec2.FIElds("Studentname").Value

rec2.MoveNext

Loop

End Sub

Private Sub Form_Load()

'注意要记住该数据库目录为你数据库文件当前的位置

Cnn.Open "ProvIDer=Microsoft.Jet.olEDB.4.0;Data Source=E:\Sample.mdb;Persist Security Info=False"

'打开student表的全部字段

rec1.Open "SELECT * FROM Student",Cnn,adOpenKeyset,adLockOptimistic

rec2.Open "SELECT * FROM Student",adLockOptimistic

'读取数据

Do Until rec1.EOF

List1.AddItem rec1.FIElds("Studentname").Value

rec1.MoveNext

Loop


Do Until rec2.EOF

List2.AddItem rec2.FIElds("Studentname").Value

rec2.MoveNext

Loop

End Sub

Private Sub Form_Unload(Cancel As Integer)

rec1.Close

rec2.Close

Cnn.Close

End Sub

VB代码结束

代码并不复杂,主要思路就是建立两个Recordset,Open的时候按一样的方式打开。用一个来修改,重新读取另一个看看数据有没有更新。现在运行程序,填写Text2为王伟。单击【用rec1修改第一个人的名字】(默认修改第一个记录)。


对比一开始的界面图,rec2只是重新读了一遍数据,同样地第一条记录林则徐被改成了王伟。Access将王伟还原为林则徐,这些数据项以后还要用的!

填写Text1为161725(不要与已有的重复就行),Text2填写吴曦,然后按【用rec1新增记录】。结果Access刷新一下显示出来了,左边的rec1的列表也显示出来了,但是右边的rec2列表却没有显示出吴曦。证明键集游标不能反映出别人的新增,同样删除也是不能反映出来的。如下图所示:



Access将吴曦的PhoneNo填为14328745601Age填为17CreateDate填为2015/09/25。这样我们就多了一条记录。

在说了键集游标之后。来看一下真正的静态游标。通过【锁与游标搭配】一节的表,我们知道,只有adOpenStatic和adLockReadonly的组合会使数据库引擎使用静态游标。静态游标的特点是只读,但是与只进游标不同的是,静态游标可以前后随意检索。前后随意检索在MovePrevIoUs,MoveNext方法中得以体现,所以就不演示了。现在我们来尝试一下用静态游标尽行新增。

代码还是用上面的,只是rec1open方法的最后两个参数改成adOpenStaticadLockReadonly,其他的代码都保持不变。填好Text1和Text2之后,按【用rec1新增记录】按钮来尝试新增。


当单击【用rec1新增记录】按钮的时候出现错误3251,错误描述为:不支持更新。这个不支持更新既是静态游标的效果,也是adLockReadonly锁的效果

最后一项是只进游标。顾名思义只前进不退,所以MovePrevIoUs是无法使用的。将rec1open方法的最后两个参数改成adOpenStatic在Form_Load的最后调用一下MovePrevIoUs就可以看到效果了。

代码开始:

Private Sub Form_Load()

'……,节约位置省略了

'打开student表的全部字段

rec1.Open "SELECT * FROM Student", adOpenForwardOnly,adLockReadonly

'……,节约位置省略了

Do Until rec2.EOF

List2.AddItemrec2.FIElds("Studentname").Value

rec2.MoveNext

Loop

'新加的这句在这里并没有什么用,只是调用一下这个方法看看效果

rec1.MovePrevIoUs ' 这里会出错

End Sub

代码结束


单击上图中的调试按钮,就可以看到出错的代码是MovePrevIoUs的调用了。


只能前进,不能后退,同时也不允许任何增删改,这就是只进游标的特点

虽然sql Server支持动态游标,但是由于Jet数据库引擎不支持,Access本身暂时无法验证,所以也就不演示了,即便在sql Server演示也意义不大。大家知道动态游标能反映所有的变动就可以了。

但是值得一提的是,只进游标是效率最高的游标,也是资源消耗最小的游标类型。如果只是为了读取数据(如用于显示),并不打算作变动,建议使用只进游标(adOpenForwardOnlyadLockReadonly),毕竟用于显示的话,只进取出每条数据来显示就足够了。在需要回退的情况下用静态游标(adOpenStatic,adLockReadonly)。在需要增删改的情况下用键集游标(adOpenKeyset,adLockOptimistic

所有游标类型功能由弱到强,资源消耗由小到大排序如下:

只进游标<静态游标<键集游标<动态游标(Jet不支持)

这一章的内容作为了解。最后一段红色字就是文章的结论。如果目前无法理解文章的内容,并不要紧。先记住结论,再来慢慢看也不迟。文章以后为了方便,统一使用键集游标。之前几篇文章中,adOpenStatic和adLockOptimistic的组合已经全部将adOpenStatic修正为adOpenKeyset

虽然这是一篇增补篇,但是却比正篇还要长。毕竟这是一般的数据库书会用两章(书的一章等于博文的两三章的篇幅)甚至更多来讲述的内容。但是我们目前还不需要了解得特别详细。


附录

得出不同游标与锁常数的组合实际使用的游标的代码。在对象浏览器中,选择库ADODB。其中可以看到游标类型的常数以及锁工作方式的常数,这里给出其VB定义:

代码开始:

Public Enum CursorTypeEnum

adOpenDynamic = 2'动态游标(Jet数据库引擎不支)

adOpenForwardOnly = 0'只进游标

adOpenKeyset = 1'键集游标

adOpenStatic = 3'静态游标

adOpenUnspecifIEd = -1'不指定游标

End Enum

Public Enum LockTypeEnum

adLockBatchOptimistic = 4'开放式批锁定

adLockOptimistic = 3 '开放式锁定

adLock@R_239_3270@ = 2'保守式锁定

adLockReadonly = 1'只读锁定

adLockUnspecifIEd = -1'不指定锁定

End Enum

VB代码结束

接下来是试验用的代码。注意不要将上面的定义也写到代码里,否则就和ADODB库的重复了。

代码开始:

Dim Cnn As New ADODB.Connection

Dim rec As New ADODB.Recordset

Private Sub Form_Load()

'注意要记住该数据库目录为你数据库文件当前的位置

Cnn.Open"ProvIDer=Microsoft.Jet.olEDB.4.0;Data Source=E:\Sample.mdb;Persist Security Info=False"

'按不同方式打开记录集

For i= -1 To 3'游标类型,从-13

For j = 1 To 4'锁工作方式,-1(没测试),14

rec.Open "SELECT * FROM Student",i,j

List1.AddItem i & "&"& j

List2.AddItem rec1.CursorType &"&" & rec1.LockType

rec.Close

Next

'每一个游标后插入一个空行,方便看

List1.AddItem ""

List2.AddItem ""

Next

End Sub

Private Sub Form_Unload(Cancel As Integer)

Cnn.Close

End Sub

代码结束

运行界面很简单,就是上面演示的界面少了那两个文本框和按钮。

总结

以上是内存溢出为你收集整理的VB6基本数据库应用(十):【增补篇】游标Cursor和锁Lock简介全部内容,希望文章能够帮你解决VB6基本数据库应用(十):【增补篇】游标Cursor和锁Lock简介所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/1268545.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-08
下一篇 2022-06-08

发表评论

登录后才能评论

评论列表(0条)

保存