问题
我有一个VB6应用程序,它使用Microsoft Access作为后端。该应用程序用于多用户环境。最近,由于没有对应用程序进行任何更改,我们在数据库的一个表中看到一些记录没有被保存,而其他记录被保存两次,或者甚至一次甚至3次。
详情
它是一个以Access 2002作为后端的VB6应用程序。该应用程序安装在运行Windows 2008 Server的计算机上。网络上的多个用户在他们的计算机上有一个应用程序的快捷方式,他们一次运行应用程序,访问相同的数据库但不同的记录。
应用程序使用以下逻辑将记录保存到数据库:
1
If objectID > 0
' existing record
sql = "UPDATE myTable SET a=..., b=..., etc WHERE Id = objectID"
cn.Execute sql
Else
' new object; create new record
nextID = "SELECT Max(id) + 1 FROM myTable"
sql = "INSERT INTO myTable (a,b,c) VALUES (...)"
cn.Execute sql
objectID = nextID
End If
Exit Function
Err_Handler:
' handle the case where two people get the same ID
If timeNotExpired Then
' Try saving again;
Resume 1
Else
' Could not save; display error
End If
因此,在保存记录时,如果它存在则更新,否则它会被插入。主键字段是通过调用Max(ID)+ 1获得的。通过此设置,Max(ID)+ 1可能为两个保存到同一个表的用户返回相同的ID。同时。如果发生这种情况,应用程序将返回到标签1所在的位置,并且再次调用Max(ID)+ 1,直到没有冲突或直到保存操作超时。简单。
上周,在没有对应用程序进行任何更改的情况下,它刚刚开始发生(1)一个表中的记录将随机不保存,或者(2)同一个表中的给定记录将显示在数据库中两次甚至3次。换句话说,该表中的记录将不止一次出现在数据库中。
它不会一直发生,但每天发生5-10次。请注意,全天至少有5人使用该应用程序,主要用于数据输入。如果给定记录未正确保存,则数据不同步,应用程序将显示消息。此时,如果我检查数据库,我会看到记录丢失或重复。通常,当一个人遇到这种情况时,它也会发生在同样输入数据的其他用户身上。同时。
修改 让我添加更多上下文...我有两个表(以及其他表),表示客户/订单方案中的父/子关系。父级必须至少有一个子级,并且应用程序已进行检查以确保父级未保存到数据库,除非用户已为其添加了至少一个子级。如果用户添加没有任何子女的父母,则用户可能无法继续对该应用程序执行任何操作。保存父母(和孩子)的数据库代码有一个if语句,读取"如果parentHasNoChildren退出函数"的行。 绝对没有办法,完全没办法,绝对没有办法......对于运行代码的应用程序而言,这会导致父级被保存到没有子级的数据库中的
但是唉,从上周开始,对应用程序完全没有任何修改,我们在数据库中看到没有孩子的父母。每个用户每天大约发生10次问题。
我已经修改了应用程序,以便在用户找到没有子级的父级时提醒用户。如果是这样,程序会指示他们删除记录并再次添加,之后一切都很好。
现在,父母在没有孩子的情况下到达数据库的事实只能意味着(1)应用程序试图保存孩子,(2)Access没有返回任何错误,表现得像一切正常,(3)应用程序& #34;认为一切都是桃子"事实上,孩子根本没有得救。我知道Access没有返回错误,因为应用程序记录了保存操作期间发生的每个错误。我检查了日志,没有关于孩子没有被保存的错误。
编辑2 :(我相信我发现了问题!)
检查数据库后,我发现子表中的主键已经消失。也就是说,应该设置为主键的字段在那里,但它不被设置为主键。我不知道这是怎么发生的。数据库设计还没有被触及,所以我假设MS Access有一天醒来并说#嗯嗯,我想知道如果我从这个表中删除了主键会发生什么......&# 34;
无论如何,我相信这肯定是我问题的原因。设置主键以防止重复输入。密钥消失后,可以使用相同的ID保存两个子记录。由于我的代码使用Max(ID)+1来生成新子记录的ID,因此Max(ID)+1可能会为尝试保存子记录的多个用户返回相同的ID。同时。这在过去不会成为问题,因为Access会产生关于重复ID的错误,应用程序会检测错误并再次执行Max(ID)+1。但是如果没有主键,则会使用相同的ID保存两个子记录。然后,如果任何用户对其中一个记录进行了更改,则两个记录都将更新,并且两个记录的所有字段(包括父记录的外键,parentID)都将设置为相同的值。这将导致一个父母没有孩子,另一个父母有重复的孩子。我的天哪真是太乱了!
我只是尝试将主键添加到表中,但我不能,因为我必须找到并删除重复的记录。在我能够添加主键之后,我会将最终结果作为答案发布。感谢你的帮助。
现在最后一点说明:有问题的表是数据库中最大的,包含超过350万条记录。该表有22个字段,其中20个是长整数,一个是字段大小为100的文本字段。另一个是布尔字段。
我做了什么
由于应用程序没有改变,我立即假设(并继续假设)问题是MS Access数据库中的损坏。我做了以下事情:
我还会用精梳梳理一下这个应用程序,看看我是否找到了任何东西,尽管一切都指向Access是罪魁祸首
任何想法?
以前有没有人遇到这样的情况?大约10年前,我自己在同一个数据库中遇到了类似的问题。那时候,我得到的是#34;无法识别的文件格式"错误,这是数据库损坏的明显例子。我通过创建一个新数据库并导入表来修复它,但这次没有帮助。有什么想法吗?
答案 0 :(得分:0)
我会检查ID列的数据类型,并确保它足够大。考虑将其更改为计数器数据类型,而不是运行域功能(MAX(ID)),或尽可能使用复制ID。这就是你的问题可能发生的地方。
之前我已将ID设置为LONG,并在另一个表中维护自己的计数器。也许是一个包含NextID列的表,以及一个获取此ID并为下一个人更新+ 1的VBA函数。在事务中,这可能比MAX更可靠,MAX必须与锁竞争。
祝你好运!答案 1 :(得分:0)
事实证明,问题源于Microsoft Access删除了数据库中两个表的主键。因为我使用Max(ID) + 1
来获取新记录的ID,并且有多个用户一次创建新记录,所以相同的ID有时用于多个记录。这导致了上述问题。
为了解决这个问题,我只是在删除了找到的任何重复条目后添加了密钥。
我还会尝试清除Max(ID) + 1
以获取@DanielG建议的新记录。
如果其他人不幸在多用户环境中使用MS Access,我建议遵循文章How to keep a Jet 4.0 database in top working condition中列出的Microsoft建议。
谢谢大家的帮助!