【问题标题】:Is there a way to lock record in Access database有没有办法锁定Access数据库中的记录
【发布时间】:2019-03-26 15:23:21
【问题描述】:

我需要找到一种在多用户环境中从 MS Access 数据库中获取唯一“验证”的方法。这是我的表格示例:

字段验证已预先填写并且永远不会更改,mID 和 getDate 由用户添加/删除(使用 VBA 脚本)。
VBA 脚本的规则是:
1.找到mID的第一个空闲行,
2. 填写当前用户名和当前日期,
3.返回对应的Verification字段

似乎很容易做到,这是我开发的代码:

Function access() As String

    Dim con As ADODB.Connection
    Dim Records As ADODB.Recordset
    Dim record As ADODB.record

    Set con = New ADODB.Connection
    Set Records = New ADODB.Recordset
    Set record = New record

    con.ConnectionString = sDBPath
    con.Open

    With Records
        .ActiveConnection = con
        .Source = "tblVerificationNr"
        .LockType = adLockOptimistic
        .CursorType = adOpenDynamic
        .Open

    Do Until .EOF
        If IsNull(.Fields("mID")) Then
            access = .Fields(1)
            .Fields("mID") = "asdf"
            .Fields("getDate") = Now
            .Update
            Exit Do
        End If
        .MoveNext
    Loop

    End With

End Function

代码适用于 1 个用户,但当多个用户(几乎)同时开始查询它时,他们会收到相同的验证码。 (如果用户 2 比用户 1 晚 0.1 秒发送请求,那么他们会找到同一行 - 验证 = 3006。这将导致第一个用户 1 将输入他的 mID 和 getDate 并且将收到验证 = 3006,但用户 2 晚了 0.1 秒将覆盖此数据并接收相同的验证号)。

对此有什么解决方法?如何保证 Verification 的唯一性?是否可以“锁定”用户 1 找到的记录,使用户 2 无法找到该记录?

用 SQL 语句也试过了:

sSelectSQL = "SELECT TOP 1 tblVerificationNr.VerificationNumber, tblVerificationNr.Mid, tblVerificationNr.getDate FROM tblVerificationNr WHERE (((tblVerificationNr.[mID]) = '" & UserName() & "')) ORDER BY tblVerificationNr.getDate DESC, tblVerificationNr.ID"
sUpdateSQL = "UPDATE (SELECT TOP 1 tblVerificationNr.VerificationNumber, tblVerificationNr.Mid, tblVerificationNr.getDate FROM tblVerificationNr WHERE (((IsNull([tblVerificationNr].[mID]))<>False)) ORDER BY tblVerificationNr.VerificationNumber)  AS a SET a.mID = '" & UserName() & "', getDate = '" & Now() & "'"

这里也是同样的问题。

【问题讨论】:

  • 我认为你最好在 SQL 中使用 update/insert 和 where 子句来解决这个问题?类似的东西update tblVerificationNr set mid='Nathan' (select min(id) where mid is null and getdate is null) 新 ID 将是 (select min(id) where mid is null and getdate is null)
  • @HansUp 版本应该可以在条件参数中没有 [ ] 的情况下工作。在 VBA 中,将这些引号更改为撇号。即使使用 SQL,用户获得相同记录的机会仍然非常非常小。我使用这种方法,从来没有遇到过问题。但是,代码不处理没有“空”记录的可能性。
  • 想了很多,但 [ ] 并不是真正需要的,因为字段名称没有空格或特殊字符,但它们不会造成伤害。
  • 已经预填验证的任何理由?如果您将Insertqueries 与唯一索引一起使用,则更容易防止用户发生冲突。因此,如果可能的话,每次都创建一个带有插入的新行。如果用户冲突,只有第一个可以插入数据,后面的会收到错误,可以尝试下一个验证号。如果必须预先填写验证,请使用第二个表并将验证、用户名和日期插入该表。
  • 是的,这是个好主意,对新记录有帮助,但无论如何,当用户删除某些值时,我仍然需要填写空记录(请参阅我的屏幕截图中的 ID=6)

标签: sql excel vba ms-access


【解决方案1】:

我很惊讶用户得到相同的数字。尝试adLockPessimistic,而不是拉整个表,只拉 1 条记录。

.Source = "SELECT TOP 1 * FROM tblVerificationNr WHERE mID IS NULL ORDER BY ID;"

如果您愿意,可以按 VerificationNumber 排序,但可能要确保排序字段已在表中编入索引。

然后不要循环,只设置字段的值:

If Not .EOF Then
    .Fields("mID") = "asdf"
    .Fields("getDate") = Now
    .Update
    access = .Fields(1)
End If

【讨论】:

  • 谢谢你,但同样的问题 - 对 1 个用户有效,但当 2 个用户在 1 秒内发送请求时,他们会收到相同的结果。这是否可能是一些 Aceess 选项 - 我尝试了不同的“默认打开模式”和“默认记录锁定”选项,但仍然相同。这可能是一些“共享驱动器”配置吗? (存储 DB 的地方)。
  • @MichałPlich:检查.LockTypeafter.OpenCursorLocation需要更改为adUseServerLockType
猜你喜欢
  • 2016-07-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-04
  • 2012-06-22
相关资源
最近更新 更多