权宜之计004:冲突只能回避啊

本文探讨了在Access数据库中使用子窗体时遇到的写入冲突问题,并分享了两种尝试过的解决方法及其不足之处。最终提出了一种有效解决方案,即利用BeforeUpdate事件取消原操作并直接更新数据库。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、问题描述

有个绑定数据表的子窗体,改了其中一个字段(该字段绑定到一个文本框)的值之后,希望同一记录的另外一个字段的值做相应变化,另外也引起其他表和控件的一系列变化。

这所有相关变化我事先写了个函数,因为还有好几处别的地方要用它。

我在该文本框的afterupdate事件过程里调用了这个函数,之后在子窗体中移动到下一条记录,就会有写入冲突。原因我也明白,因为子窗体上改动了这个记录,还没彻底改完,我又在所调用的函数里通过ADO又改动了同一记录,而子窗体的记录集一般缺省是DAO的。这样就造成两种途径同时访问同一记录。

二、2种未遂的解决方法
我试了下面两种方式处理这个写入冲突,都不太好使。

第一种思路是来自http://www.accessoft.com/bbs/showtopic.asp?ID=700
1.用VBA断开与窗体的绑定
application.echo =false'此行解决操作员看不见画面的变化
me.recordsource =""

2.再执行表中记录的操作

3.用VBA实现与窗体的绑定
me.recordsource ="SQL语句"
application.echo =True

这个思路的缺点在于,执行之后,我的子窗体不再能正确地显示主窗体的内容,好像失去了和主窗体的联系。

第二个思路是,不在afterupdate事件过程里调用我的函数,而在afterupdate事件之后的事件过程里调用我的函数。可是这个也行不通,因为我无法确定,afterupdate事件之后必然发生的有什么事件。因为这是个子窗体,当我改变了子窗体的数据,然后点击主窗体里的控件后,子窗体控件的exit lostfocus事件均不发生。

 

三、权宜之计
最后,我只好把我调用的那个函数加了个布尔参数,如果是来自子窗体的调用,则不执行那段改动字段值的代码,而把这段代码直接放到文本框的afterupdate事件过程里做。

虽然问题算凑合解决了,可还是挺不爽的。有没有什么更好的解决写入冲突的办法啊?比如我有没有可能在afterupdate事件过程里强制更新数据,然后之后我再用ADO改同一记录就不会产生写入冲突了?还有我上面失败的两个思路,是不是真的就不行还是我的具体操作有问题?

 

四、后记

这种冲突的本质还有另一方面,就是事件机制。就是事件只能轮流执行,在事件A过程里激发另一个事件B的话,事件B处理完之后,事件A才算处理完。所以,在上面的权宜之计后,我又进一步完善了解决冲突的方法。就是我会在子窗体的控件的afterupdate事件过程里触发事件B;在这个事件B的过程里做改变子窗体绑定记录以为的变化,然后触发事件C、让子窗体做一些自己绑定记录的变化;然后再触发事件D,让父窗体更新显示(从而也更改子窗体的当前记录);最后再回到afterupdate事件过程的末尾。上述思路的伪代码如下:

子窗体控件 _AfterUpdate()
……
    RaiseEvent B
……
End Sub

B()
   '改动非绑定数据
    ……
   
    '子窗体改动绑定记录
    RaiseEvent C

   '父窗体更新显示
    RaiseEvent D
……
End Sub

 

五、后后记

我终于找到了一个解决这个问题的办法,就是在beforeupdate取消这个操作,具体如下:

Private Sub strName_BeforeUpdate( Cancel As Integer)
    Dim strFv() As String
   
    Cancel = True
    Me . strName . Undo '不undo就不能对dirty赋值
     Me . Dirty = False
   
    ReDim strFv( 1)
    strFv( 0) = "bytMultiGua=3"
    strFv( 1) = "strName=" & Me . strName
    Call ChangeDetailInTableDAO( "action" , Me . lngId , strFv)
    Erase strFv
End Sub

像上面这样写就不会有写入冲突了。即使我那个函数ChangeDetailInTable用的ADO,也没事。我理解这3个貌似重复的语句,起了不同的作用,分别在和不同的对象或系统打招呼。

Cancel = True '这一句是和事件系统打招呼,让后续的事件不再发生
Me . strName . Undo '这一句是和数据引擎打招呼,取消某种锁定状态,不undo就不能对dirty赋值
Me . Dirty = False '这一句是和窗体打招呼,这样窗体移到下一条记录的时候,不会更新

我发现undo这个方法很奇怪。貌似它并不真的undo,而只是解锁。就是解掉数据库被更改不允许操作的状态,而控件的值,其实还是新值,并没有像在word里那样被undo回老值。

还是感谢Tiger_Zhao,他提醒我:一个程序只用一个连接,最主要不是避免“写入冲突”,而是保证数据的一致性。数据对象操作数据库是可能存在缓存的,如果你用多个连接(特别是 ADO 和 DAO 异种连接),难免会发生A连接做了更新、而B连接读取的数据没有反映最新的更新。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值