我建立了一个Access数据库。它最初是为 6 人准备的,但我看到它最多 20 人,所以这可能是问题所在。无论如何,后端一天会出现几次不一致的状态。通常可以通过打开后端来解决这个问题,它提供恢复它并且通常这样做。
回答评论中的一个问题:发生的情况是前端不再能够读取后端中的任何表,因此引发错误。
当我打开后端时,状态如下:
Microsoft Access 检测到此数据库处于不一致状态,并将尝试恢复该数据库。在此过程中,将制作数据库的备份副本,并将所有恢复的对象放入新数据库中。然后 Access 将打开新数据库。未成功恢复的对象名称将记录在“恢复错误”表中。
唯一的选择是按“确定”。通常,这可以在原地完成,但是当我在 VPN 上查看文件时,有时会发现它旋转了一会儿。在这种情况下,我可以将不一致的文件复制到我的硬盘驱动器,打开它,按 OK,然后让它完成它的工作。它通常只需要几秒钟。那时它说:
Microsoft Access 已恢复此数据库。检查数据库以确认没有丢失的数据库对象。
到目前为止,除了一次我不得不去一个稍旧的备份之外,这已经成功了。
数据库不是特别复杂(我不认为),但它确实有一些 VBA。
数据库的基本思想是我们正在跟踪需要通过一组流程但被分解的批次。所以我们可能会收到 1000 个项目,然后让其中 300 个进入预筛选,然后再有 100 个,依此类推,经过大约 8 个步骤。
我这样做的方式(我很乐意改变 - 我只是不知道要改变什么)是有一个小的提交表,它跟踪进入的批次,以及一个更大的表(称为原因无关紧要的预购),它跟踪订单项。
预购表有相当多的字段(大约 75 个)。但对此重要的是数量字段和状态字段。状态字段在整个过程中跟踪项目(因此从步骤 1 = 接收到 8 = 发货或其他)。数量跟踪此批次中有多少此特定项目以及处于此状态的其他属性。
然后,这些步骤中的每一个都有表单,后面有非常相似的 VBA。其中一个字段基本上是“移动到下一步的数量”(这是预购表中最初默认为 0 的字段之一)。用户填写此数量(可能还有一些附加信息)并按下按钮来处理该步骤。
VBA:
- 为预购表打开一个记录集 (rs),其中状态为 1(比如说),并且要进行下一步的数量大于 0。
- 它还打开预排序表 (rs2) 的 appendonly 记录集。
- 然后它遍历 rs 中的记录,向下调整数量,并附加一个新的记录副本,其中包含新的数量和更新的状态。
以下是其中一个屏幕的示例。其他的也是类似的,尽管有一些细微的差别可能很重要,也可能不重要。
Private Sub btnProcess_Click()
DoCmd.Hourglass True
Dim db As Database
Dim rs As DAO.Recordset
Dim rs2 As DAO.Recordset
Set db = CurrentDb
Set rs = db.OpenRecordset("SELECT * FROM tblPreorder " & _
"WHERE (((tblPreorder.StatusID)=1) AND ((tblPreorder.PSQuantity)>0));", dbOpenDynaset, dbFailOnError)
If rs.EOF Then
MsgBox "No records found for processing"
rs.Close
DoCmd.Hourglass False
Exit Sub
End If
Set rs2 = db.OpenRecordset("tblPreorder", dbOpenDynaset, dbAppendOnly)
rs.MoveFirst
Do Until rs.EOF
myQuantity = rs("Quantity").Value
PSQuantity = rs("PSQuantity").Value
rs2.AddNew
For Each fld In rs.Fields
SFld = fld.Name 'to catch special fields
Select Case SFld
'special cases
Case "ID": 'do nothing
Case "Quantity":
rs.Edit
rs(SFld).Value = myQuantity - PSQuantity
rs.Update
rs2(SFld).Value = PSQuantity
Case "Comment":
If Len(Trim(rs("PSComment")) > 0) Then
rs2(SFld).Value = Trim(rs("Comment")) & vbCrLf & Trim(rs("PSComment"))
Else
rs2(SFld).Value = rs(SFld)
End If
Case "StatusID":
rs2(SFld).Value = 2 'Changes the status from 1 to 2
Case "DateChanged":
rs2(SFld).Value = Now()
Case "EmployeeID":
rs2(SFld).Value = UserID()
Case "Location":
If rs("PSLocation") <> "" Then
rs2(SFld).Value = rs("PSLocation")
End If
Case "PSDate":
rs2(SFld).Value = Now()
Case "PSEmployeeID":
rs2(SFld).Value = UserID()
Case "PSQuantity":
rs.Edit
rs(SFld) = 0
rs.Update
rs2(SFld) = 0
Case "ReleasedFiles": 'do nothing
Case Else:
rs2(SFld).Value = fld.Value
End Select
Next fld
rs2.Update
rs.MoveNext
Loop
rs.Close
rs2.Close
c = Me.CurrentRecord
Me.Requery
On Error Resume Next:
DoCmd.GoToRecord acDataForm, Me.Name, acGoTo, c
MsgBox "Items moved to BNC Request"
DoCmd.Hourglass False
End Sub
我的问题:
- 当然,如果您发现任何明显错误的地方,请告诉我。当它只是我测试它时,它就像一个魅力。我从来没有设法复制这个问题,但我可以看到它正在生产版本中发生。
- 我已经遵循了几个网站上关于避免这种情况的建议(例如https://www.techrepublic.com/article/get-it-done-top-10-ways-to-prevent-access-database-corruption/)。我基本上是在修补和尝试,因为我根本不知道问题是什么。例如,我在上面的代码中从记录集切换到 DAO.recordset。好像没什么区别,所以我可能会回去。每个人都在使用 Access 365,而后端是 Access 365,因此使用 Access 特定的记录集似乎很有意义。我关闭所有记录集(rs.close);我编译VBA;我已将前端保存为acde;所有用户在自己的电脑上使用acde;所有用户都使用有线连接;我有版本控制,所以每个人都在使用最新的前端。
- 我想主要问题是:我该如何诊断?我可以很容易地想象放入一个新表来跟踪谁在按下进程按钮以及何时以及哪一个。我可能会这样做,看看在导致腐败的过程中会发生什么。但是,您对跟踪什么有什么建议,是否有任何其他技巧和提示可以解决这个问题?
代码特定问题:
- Recordset 或 DAO.Recordset 或其他什么东西?
- dbFailOnError 或 dbSeeChanges 或其他什么东西?
- rs.Edit ... rs.Update 在我循环时更新的几个字段(当前代码)?还是在循环的任一侧都有一个 rs.Edit ... rs.Update?
- 我应该手动保留或阻止人们同时运行类似的代码吗?这样做有点冒犯了我,因为我有点想象制作 MS Access 的人在这种事情上会比我做得更好。但我可能会在某个地方设置一个标志,让人们等待轮到他们。我仍然会担心比赛条件。
更广泛的数据库问题:
- 是否需要调整其他秘密设置以尽量减少此问题?每个人都在使用 MS Access 365。命名自动更正选项、过滤器查找选项、缓存、数据类型支持选项。我真的不知道这些做什么,我怀疑到处都有陷阱!我有一个类似的数据库,多年来一直没有问题,所以我在这里陷入了一种错误的安全感。
- 我的结构完全错误吗?我可以做一大堆工作——如果能很好地了解它会解决问题,那就太好了!