局域网多用户共用表
在程式运行时用哪种方式打开DBF文件 可以不影响其他用户也使用这个表呢?
现在情况是某个表 当有人打开之后 其他人要用的话就会提示 文件不能存取!
怎么解决呢?
[解决办法]
数据共享程序设计
如果创建的应用程序在网络环境中的多台计算机上运行,或者一个表单的多个实例对相同的数据进行访问,这时就需要进行共享访问程序设计。共享访问不仅能为用户使用数据和数据共享提供更有效的方法,而且可以在必要时对访问进行限制。
VFP支持如下功能:对数据的共享或独占访问;锁定选项;数据工作期;记录缓冲和表缓冲以及事务处理。尽管这些功能主要应用在共享环境里,但在单用户环境下也可以使用。
一、控制对数据的访问
因为访问数据是在文件里进行,所以有效的数据管理首先从控制这些文件开始。您需要选择访问数据的方式,还要选择在什么时间、如何限制对数据的访问。
1、访问数据
在共享环境中,可以用两种方式访问数据:从独占文件中访问或从共享文件中访问。若打开一个共享访问的表,其他用户也可以对该文件进行访问;若打开一个独占访问的表,其他用户就不能对该表进行读写。独占访问不具备在网络环境中共享数据的许多优点,所以应该避免使用。
1)以独占方式使用表
打开一个文件最严格的限制方式就是独占方式。通过界面打开一个表时,默认情况下是独占使用的,也可以利用VFP命令明确地以独占方式打开一个表。
如果要打开一个独占使用的表,可以在命令窗口中输入如下命令:
SET EXCLUSIVE ON
USE cMyTable
或者在命令窗口中输入:
USE cMyTable EXCLUSIVE
下列命令要求以独占方式打开一个表:
·ALTER TABLE
·INDEX:当创建、添加或删除一个复合索引标志时。
·INSERT [BLANK]
·MODIFY STRUCTURE:如果要以此命令更改一个表结构,必须以独占方式打开该表。但是,当以共享方式打开这个表时,只能在只读方式下使用此命令。
·PACK
·REINDEX
·ZAP
在一个共享表中执行上述命令,VFP将返回出错信息:“文件必须以独占方式打开”。
可以使用FLOCK()函数限制对表的访问。如果使用FLOCK()锁定表,则其它用户不能对该表进行写操作,但可以读该表。
2)以共享访问方式使用表
以共享方式打开一个表时,多个工作站可以同时访问该表。通过界面打开表时,可以不理会SET EXCLUSIVE默认的ON设置,而明确地用VFP命令打开一个表供共享使用。
若要打开一个共享使用的表,可以在命令窗口中输入下列命令:
SET EXCLUSIVE OFF
USE cMyTable
或者:
USE cMyTable SHARED
当在一个共享表中添加或更改数据时,必须首先锁定要更改的记录或整个表。对一个以共享方式打开的表或记录,可通过下列方式进行锁定:
·使用命令来自动锁定记录或表。
·用记录和表锁定函数,人工锁定一个或多个记录。
·用CURSORSETPROP()函数设置缓冲。
与共享表相关的备注和索引文件也是以共享方式打开的。如果应用程序所使用的表只用于查找数据,而该应用程序的所有用户都要访问它,那么将该表标记为只读可以提高性能。
2、锁定数据
如果要共享访问文件,必须通过锁定表和记录来对这种访问进行管理。锁定不同于访问允许权限,它既可以对数据进行长期控制,也可以短期控制。VFP提供自动和人工锁定方式。
1)选择记录或表锁定
无论是哪一种锁定方式,目的都是为了防止两个用户同时写一个记录。表锁定用来防止其他用户向表中写入,但允许读整个表。由于表锁定阻止其他用户更新表中的记录,因而很少使用。
2)人工或自动锁定
除了选择记录锁定还是表锁定,还可以选择自动锁定或人工锁定,许多VFP命令在执行之前都会自动锁定一个记录或一个表,如果成功锁定了记录或表,则继续执行该命令,然后再解锁。下面列出了自动锁表和记录的命令:
命令 锁定范围
——————————————————————————
ALTER TABLE 整个表
APPEND 整个表
APPEND BLANK 表头
APPEND FROM 整个表
APPEND FROM ARRAY 表头
APPEND MEMO 当前记录
BLANK 当前记录
BROWSE、CHANGE和EDIT 一旦开始编辑字段,锁定对象为当前记录和相关表中别名字段的所有记录
CURSORSETPROP() 取决于参数
DELETE 当前记录
DELETE NEXT 1 当前记录
DELETE RECORD n 记录n
DELETE 删除多个记录 整个表
DELETE-SQL 当前记录
GATHER 当前记录
INSERT 整个表
INSERT-SQL 表头
MODIFY MEMO 编辑开始时,锁定当前记录
READ 当前记录和别名字段的所有记录
RECALL 当前记录
RECALL NEXT 1 当前记录
RECALL RECORD n 记录n
RECALL 恢复多个记录 整个表
REPLACE 当前记录和别名字段的所有记录
REPLACE NEXT 1 当前记录和别名字段的所有记录
REPLACE RECORD n 记录n
REPLACE 替换多个记录 整个表和别名字段的所有记录
SHOW GETS 当前记录和别名字段引用的所有记录
TABLEUPDATE() 取决于缓冲
UPDATE 整个表
UPDATE-SQL 整个表
3)记录锁定的特点
锁定记录的命令比锁定表的命令破坏性要小。锁定一个记录时,其他用户仍然可以添加或删除其他记录。如果记录或表已经被其他用户锁定,或者表已经被其他用户用独占方式打开,则锁定记录或表的操作失败。如果不能锁定记录,则尝试锁定当前记录的命令将返回出错信息“其他用户正在使用记录”。
BROWSE、CHANGE、EDIT和MODIFY MEMO命令只有在编辑时才锁定记录。如果您正在编辑来自相关表记录中的字段,那么该相关记录可能会被锁定。如果当前记录或相关记录已被其他用户锁定,则锁定失败。如果锁定成功,则可以编辑该记录;在移到另一个记录或激活其他窗口时,记录解锁。
4)表头和表锁定的特点
一些VFP命令锁定整个表,而有些命令则只锁定表头。表锁定命令比表头锁定命令更加严厉。锁定表头时,其他用户不能添加或删除记录,但可以修改字段内的数据。
当发出APPEND BLANK命令时,用户可以共享表而不发生冲突,但是当其他用户也向该表追加一个空白记录时,就会出错。出错信息是:“其他用户正在使用文件”。这个信息表明有两个或两个以上的用户在同时执行APPEND BLANK命令。如果无法锁定一个表,则锁定整个表的命令将返回一个错误信息:“其他用户正在使用文件”。要取消正在进行的锁定操作,可按[ESC]键。
5)自动锁定示例
在下面的示例中,即使customer表是以共享方式打开的,用户为了从其他表追加记录也将自动锁定整个表。
SET EXCLUSIVE OFF
USE customer
APPEND FORM oldcust FOR state="OPEN"
6)人工锁定
您可以用锁定函数人工锁定一个记录或一个表。这些函数有:
RLOCK() LOCK() FLOCK()
RLOCK()函数等同于LOCK()函数,都可以锁定一个或多个记录;FLOCK()锁定一个文件。LOCK()和RLOCK()函数可以用户锁定表头,如果把0作为记录编号提供给LOCK()或RLOCK(),而且测试表明表头没有锁定,则该函数将锁定表头并返回.T.。
如果锁定一个记录或一个表,那么一定要尽快解锁,以便其他用户访问。解锁可使用UNLOCK命令。
这些人工锁定函数可以完成如下操作:
*测试记录或表的锁定状态。
*如果测试表明该记录没有锁定,则将该记录锁定并返回.T.。
*如果该记录或表不能锁定,则根据SET REPROCESS的当前设置,再次进行锁定。
*返回.T.或.F.,表明锁定尝试是否成功。
注意:如果不想锁定记录,而测试该记录的锁定状态,请使用ISRLOCKED()或ISFLOCKED()函数。
如果锁定记录或表的操作失败,SET REPROCESS命令和您当前的错误处理例程将确定是否再次尝试锁定。SET REPROCESS会影响不成功的锁定结果,因此可以利用SET REPROCESS来控制锁定尝试的次数和时间。
下面的示例以共享方式打开customer表,并用FLOCK()函数锁定该表。如果该表锁定成功,则REPLACE ALL将更新该表中的所有记录,UNLOCK对该文件解锁;如果其它用户已经锁定该文件或文件中的记录,现在还不能锁定该表,则显示一条信息。
SET EXCLUSIVE OFF
SET REPROCESS TO 0
USE customer &&打开共享表
IF FLOCK()
REPLACE ALL contact; &&替换并解锁
WITH UPPER(contact)
UNLOCK
ELSE &&输出信息
WAIT "文件正被其他用户使用"
ENDIF
3、解锁数据
在共享环境下锁定记录或文件并完成了相应的数据操作后,要及时解锁。解锁的方法有很多种,在某些情况下,只需简单的移动到下一个记录就能解锁,有些情况则需要明确的解锁命令。
要解锁被自动锁定的记录,只需移动记录指针,甚至在设置了MULTILOCKS ON的情况下也是如此。而对于人工锁定的记录,则必须对记录明确地解锁。
下面列出了对人工和自动的锁定记录和表进行解锁的各种命令:
命令 效果
——————————————————————————————————
UNLOCK 解锁当前工作区内的记录和文件
UNLOCK ALL 对所有工作区的记录和文件解锁
SET MULTILOCKS OFF 建立新锁定的同时自动解锁当前锁定
FLOCK() 在锁定文件之前解锁文件中所有记录
CLEAR ALL、CLOSE ALL、USE、QUIT 对所有文件和记录解锁
END TRANSACTION 对所有的自动锁定项解锁
TABLEUPDATE() 在更新表之前解锁所有锁定项
注意:如果记录在UDF中被自动锁定,那么当移开记录指针然后又移回该记录时,锁定将会被解除。可以使用表缓冲解决这个问题。
4、使用数据工作期
为确保共享环境中的每个用户都具有安全的、正确的环境,确保表单的多个实例能独立操作,VFP提供了数据工作期。
数据工作期是对当前动态工作环境的描述。可以将数据工作期看成是一个小型数据环境,这个数据环境是在一台机器上运行一个开发的VFP工作期。每个数据工作期包括:
* 表单的数据环境中的各项备份
* 表示打开的表、索引和关系的临时表
请考虑当在多用户应用程序的各自工作站同时打开相同的表单时,会发生什么,这样可以很容易理解数据工作期的概念。这种情况下,每个工作站运行一个独立的VFP工作期,因此有自己的工作区设置以及自己表示打开的表、索引和关系的临时表。
但是,如果您在一个机器上,同一个VFP工作期,打开单个项目中的同一个表单的多个实例,则这些表单共享默认的数据工作期,它代表了单个的动态工作环境。在同一个VFP工作期中打开的表单的每一个实例使用相同的工作区设置,并且在一个表单实例中移动工作区中的记录指针会自动影响相同表单的其他实例。
1)使用私有数据工作期
如果想更多的控制表单的多个实例,可以使用私有数据工作期。当表单使用私有数据工作期时,VFP为应用程序创建的表单、表单集或工具栏中的每个实例创建一个新的数据工作期。每个私有数据工作期包括:
* 表单的数据环境中每个表、索引和关系的独立备份。
* 数目不限的工作区。
* 独立于表单基表的每个备份表的记录指针。
可用数据工作期数目只受系统内存和磁盘空间的限制。
通过设置表单的DataSession属性可实现私有数据工作期,DataSession属性有如下两个设置:
* 1-默认的数据工作期(默认设置)
* 2-私有数据工作期
如果要使用私有数据工作期,请选择下列选项之一:
* 在“表单设计器”中,将表单的DataSession属性设置为“2-私有数据工作期”。
* 在代码中将DataSession属性设置为2。例如,可输入:
frmMyForm.DataSession=2
注意:只能在设计时设置DataSession属性。运行时DataSession为只读属性。
当表单使用的是私有数据工作期时,在单个机器上,单个的VFP工作期中打开表单的每个实例使用自己的数据环境。使用私有数据工作期类似于在不同的工作站上同时运行同一个表单。
2)识别数据工作期
每个私有数据工作期是单独识别的。可以在“数据工作期”窗口中查看每个数据工作期的内容。也可以通过Load事件代码中的命令改变数据工作期的说明。
使用DataSessionID的运行时属性,可以查看每个数据工作期的识别号。下面的示例显示名为frmMyForm的表单的DataSessionID属性。
DO FORM frmMyForm
?frmMyForm.DataSessionID
如果使用NAME子句激活表单,可使用该表单的名称访问DataSessionID属性,如下面的代码所示:
DO FORM frmMyForm NAME one
?one.DataSessionID
DataSessionID属性只是用来识别特殊的数据工作期。不要更改一个表单实例的DataSessionID属性,当更改DataSessionID属性时,与数据绑定的控件会丢失它们的数据源。
3)使用多个表单实例更新数据
私有数据工作期生成各自独立的工作区,工作区包含了表单的表、索引和关系的独立备份,表单的每个备份引用了相同的基表和索引文件。当用户从表单的一个实例中更新记录时,更新该表单引用的基表。当定位到更改的记录时,就可以看到表单的另一个实例所做的更改。
如果在一个私有数据工作期对记录或表进行了锁定,其他私有数据工作期就不能再进行锁定。例如,数据工作期1的用户锁定了一个记录,数据工作期2的用户就不能锁定这个记录了。如果数据工作期1的用户以独占方式打开了一个表,数据工作期2的用户就不能打开这个表了。通过遵守其他数据工作期所做的锁定,VFP可以保护基表更新的完整性。
4)定制数据工作期的环境
由于数据工作期控制着某些SET命令的范围,可以在单一的VFP工作期中使用私有数据工作期建立自定义的SET命令设置。
例如,SET EXACT命令,控制比较不同长度字符串时使用的规则,作用于当前数据工作期。SET EXACT命令的设置为ON时,规定直到表达式末尾每个字符必须都完全匹配时,两个表达式才算相等。通过在默认的数据工作期中将SET EXACT命令设置为OFF,可以使用“模糊”搜索或相似查找;但是应用程序可能包含特殊的表单,它需要精确匹配。可以将需要精确匹配的表单的DataSession属性设置为2,使用私有数据工作期,然后将SET EXACT命令设置为ON。由于仅在使用私有数据工作期的表单使用一个SET命令,则当为一个特定的表单启用自定义工作期设置时,您可以保留整个的VFP工作期设置。
5)使自动数据工作期的设置无效
当使用表单的私有数据工作期时,在一个表单中对数据所做的更改不会自动地体现到相同表单的其他实例中。如果想让表单的所有的实例都访问相同的数据,并立即反应对公共数据做的改动,可以忽略自动数据工作期的设置。
若要使自动数据工作期设置无效,请使用命令SET DATASESSION TO 1或SET DATASESSION TO。这两个命令都将启用命令窗口以及项目管理器所控制的默认数据工作期。
5、缓冲访问数据
如果希望在更新时保护数据,可以使用缓冲技术。在多用户环境下,VFP的记录缓冲和表缓冲技术可以保护对单个记录或多个记录所做的数据更新以及数据维护操作。缓冲区可以自动测试、锁定以及解锁记录或表。
借助缓冲技术,可以很容易地检测并解决数据更新操作过程中所遇到的冲突:当前记录被复制到一个由VFP进行管理的内存区域或磁盘区域,其他用户仍然可以同时访问原来的记录。当离开该记录或以编程方式更新记录时,VFP将准备锁定该记录,确认其他用户没有做修改,然后写入编辑结果。在试图更新数据时,还必须解决冲突,若有冲突则应防止编辑结果写入原来的表。
1)选择缓冲的方法
在启用缓冲之前,应对数据环境进行评估,根据应用程序、记录以及表的类型和大小,信息的使用与更新方式以及其他因素,选择缓冲方法和锁定选项。一旦启用了缓冲,则在它被废止或关闭表之前一直保持有效。
VFP提供两种缓冲:记录缓冲和表缓冲:
* 若一次只对一个记录进行访问、修改或写操作,那么请选择记录缓冲。在一个多用户环境中,记录缓冲能够提供适当的有效性检查机制,对其他用户所做的数据更新操作影响最小。
* 如要对多个记录的更新使用缓冲,请选择表缓冲。如果想在一个表中处理多个记录或在一对多的关系中处理子表的记录,表缓冲提供了最佳的工作方式。
如果要对已有数据提供最大程度的保护,请使用VFP事务。可以单独使用事务,但是如果将事务和记录缓冲命令或表缓冲命令一起使用将会获得更好的效果。
2)选择锁定方式
VFP以两种锁定方式提供缓冲:保守式和开放式。这两种方式决定了一个或多个记录何时被锁定、优势何时、怎样被解锁。
a、保守式缓冲
在多用户环境下,保守式缓冲能防止其他用户在对某一特定记录或表进行修改时访问它。
保守式缓冲为单个记录的修改提供最安全的工作环境,但是会降低用户的操作速度。这种缓冲方式非常象FoxPro以前版本的标准锁定机制。此外,它还带有内在数据缓冲等更多的好处。
b、开放式缓冲
开放式缓冲是更新记录的有效方法,因为锁定只在写记录时生效,这样在多用户环境中使单个用户独占系统的时间最少。
当在一个远程表上使用记录或表缓冲时,VFP将强制使用开放式锁定。由函数CURSORSETPROP()设置的Buffering属性值决定了缓冲和锁定的方法。
下面列出了Buffering属性的有效值:
若要启用 请使用此缓冲值
————————————————————————————————————
无缓冲,默认值 1
保守式记录锁定。它锁定当前记录,在记录指针移动或 2
发出TABLEUPDATE()命令后更新
开放式记录锁定。它一直等到记录指针移动,然后锁定 3
并更新。
保守式表锁定。它锁定当前记录,在发出TALBEUPDATE() 4
命令后更新。
开放式表锁定。它一直等到发出TABLEUPDATE()命令,然后 5
锁定并更新已编辑的记录。
对于表,Buffering的默认值为1;对于视图,默认值为5。如果您使用缓冲访问远程数据,则Buffering属性可以是3(开放式记录缓冲)或5(开放式表缓冲)。此外,对除1以外的缓冲方式,设置MULTILOCKS为ON。
3)启用记录缓冲
可用CURSORSETPROP()函数启用记录缓冲。
若要在当前数据区启用保守式记录锁定,请使用如下函数和参数:
CURSORSETPROP("Buffering",2)
VFP在指针位置锁定记录。如果锁定成功,VFP将该记录放入缓冲区并允许编辑。当移动记录指针或发出TABLEUPDATE()命令时,VFP将把缓冲记录写入原来的表。
若要在当前数据区启用开放式记录锁定,请使用如下函数和参数:
CURSORSETPROP("Buffering",3)
VFP将指针位置的记录放入缓冲区并允许编辑。当移动记录指针或发出TABLEUPDATE()命令时,VFP将对该记录进行锁定。若锁定成功,VFP将对磁盘上的记录的当前值与原来的缓冲区值进行比较。如果两值相同,则编辑结果写入原来的表;否则将发出错误信息。
4)启用表缓冲
可用CURSORSETPROP()函数启用表缓冲。
若要在当前数据区对多个记录启用保守式锁定,请使用如下函数和参数:
CURSORSETPROP("Buffering",4)
VFP在指针位置锁定记录。如果锁定成功,VFP将该记录放入缓冲区并允许编辑。使用TABLEUPDATE()命令把缓冲记录写入原来的表。
若要在当前数据区对多个记录启用开放式锁定,请使用如下函数和参数:
CURSORSETPROP("Buffering",5)
在发出TABLEUPDATE()命令之前,VFP把记录写入缓冲区并允许编辑,然后VFP对缓冲区内的每一个记录执行下列操作:
* 对每一个已编辑记录锁定。
* 一旦锁定成功,即对磁盘上的每一个记录的当前值与原来的缓冲区值进行比较。
* 如果两值相等,将编辑结果写入原来的表。
* 如果两值不相等,给出错误信息。
在启用表缓冲之后,VFP只在TABLEUPDATE()命令之后更新。