Access VBA执行DoCmd.FindRecord后窗体编辑出现写入冲突报错
故障现象
触发异常的代码
strSQL = " select top 1 id from employees " Set rs = CurrentDb.OpenRecordset(strSQL) If Not rs.EOF Then DoCmd.FindRecord rs(0), , True, , True rs.Close End If
- 代码运行后触发写入冲突错误,窗体上的「保存记录」按钮呈灰色不可用状态
- 经排查问题由
DoCmd.FindRecord语句导致 - 功能正常部分:用户输入已存在ID时自动跳转至对应记录的逻辑可正常运行
- 异常表现:跳转后尝试编辑窗体内容时,系统弹出报错提示其他用户正在使用同一窗体,暂未找到修复方案
故障原因
默认参数调用CurrentDb.OpenRecordset打开表记录集时,会以可编辑的动态游标模式加载,自动持有对应记录的读写锁。原代码在记录集未关闭、锁未释放的状态下直接调用DoCmd.FindRecord跳转至同一条记录,此时窗体绑定的记录源需要申请该记录的编辑锁,和之前记录集持有的锁产生冲突,就会触发写入冲突、锁占用类报错。原代码将rs.Close放在FindRecord执行之后,锁释放时序错误,无法避免冲突。
修复方案
方案1:调整记录集打开模式与锁释放时序
将记录集改为只读快照模式打开(不持有写入锁),在执行跳转操作前提前关闭记录集、释放所有资源,从根源避免锁冲突,修改后代码如下:
Dim strSQL As String Dim rs As DAO.Recordset Dim targetId As Variant strSQL = "SELECT TOP 1 id FROM employees" ' 以只读快照模式打开记录集,不申请写入锁 Set rs = CurrentDb.OpenRecordset(strSQL, dbOpenSnapshot) If Not rs.EOF Then targetId = rs(0) ' 读取到目标ID后立刻关闭记录集,提前释放锁 rs.Close Set rs = Nothing ' 锁释放完成后再执行记录跳转 DoCmd.FindRecord targetId, , True, , True End If ' 兜底回收对象资源 If Not rs Is Nothing Then rs.Close Set rs = Nothing End If
方案2:通过窗体记录书签定位(推荐)
放弃使用DoCmd.FindRecord,直接操作窗体绑定的记录集副本做定位,不需要额外申请独立的记录锁,是Access窗体定位记录的稳定实现方式,不会触发锁冲突:
Dim strSQL As String Dim rs As DAO.Recordset Dim targetId As Long strSQL = "SELECT TOP 1 id FROM employees" Set rs = CurrentDb.OpenRecordset(strSQL, dbOpenSnapshot) If Not rs.EOF Then targetId = rs!id rs.Close Set rs = Nothing ' 基于窗体自身的记录源做定位 With Me.RecordsetClone .FindFirst "id = " & targetId If Not .NoMatch Then ' 匹配成功后通过书签同步窗体当前记录 Me.Bookmark = .Bookmark End If .Close End With End If
注意:Access绑定窗体编辑记录时会自动申请当前记录的写入锁,任何提前持有同表同记录锁的对象(比如未关闭的可编辑记录集)都会触发锁冲突,表现为保存按钮置灰、提示其他用户占用记录,操作记录跳转前必须确保所有独立打开的相关记录集已经释放锁。
内容的提问来源于stack exchange,提问作者Dan
相关产品推荐
相关产品推荐

