在Microsoft Access VBA中一次将数据库表锁定到一个用户

时间:2017-02-18 07:26:35

标签: vba ms-access locking race-condition acid

我想知道是否可以一次将数据库表锁定到一个用户以在数据库上执行ACID术语,并且在使用VBA的Microsoft Access数据库中一次允许一个完整事务。我正在寻找伪代码中的以下内容:

  • 锁定所有表格(或某些表格)。
  • 执行所有SQL或其他内部操作。
  • 执行交易并解锁所有表格(或某些表格)。

但是,在客户端失败的情况下,例如客户端应用程序挂起,用户必须在客户端应用程序仍在处理事务时强制关闭它,它将还原更改并且从不实际执行事务,并解锁锁定。我正在寻找的是一个READ和WRITE锁,以及在数据库已被锁定时试图锁定数据库的客户端,它必须等到它被解锁?

2 个答案:

答案 0 :(得分:1)

在工作区的交易中包裹您的交易:

Dim wks     As DAO.Workspace
Dim dbs     As DAO.Database

Set wks = DBEngine(0)
Set dbs = wks.Databases(0)

wks.BeginTrans
    ' Do stuff using dbs and DAO.
wks.CommitTrans

Set dbs = Nothing
Set wks = Nothing

如果有可能发生错误,请包含一个跳过CommitTrans并调用的错误处理程序:

wks.RollBack

答案 1 :(得分:0)

实际上,我找到了一种方法来模拟单个用户访问,通过一个组合的hacky锁类型进行读写。以下将描述我是如何实现它的。

所以,我在访问中创建了一个名为Lock的小表,并且有一个名为SomeValue的列。此列必须是主键,并且它可以是任何值,因此我将其设置为类型编号,例如。此表将存储将在其中生成的所有锁,并且尝试获取锁的边必须就锁的值达成一致。例如,两个客户端将尝试获取值1的锁,因此他们应该请求锁1,并释放锁1。

首先,这里是我设置和释放锁的两个帮助程序查询,方法是将锁的值传递给试图获取它的边:

SetLock查询:

INSERT INTO Lock (SomeValue)
VALUES ([GetLockValue]);

ReleaseLock查询:

DELETE *
FROM Lock
WHERE SomeValue=[GetLockValue];

然后,这里是TrySetLock函数(它将尝试设置传入的值的锁定,并返回设置结果,其中1是传递,0是失败)和SetLock Sub(将等待直到传入的值的锁是空的以获取它 - 它使用自旋锁定方法来获取锁:)

Public Function TrySetLock(LockValue As Integer) As Integer
    Dim dbs As dao.Database
    Dim qdf As dao.QueryDef
    Set dbs = CurrentDb
    Set qdf = dbs.QueryDefs("SetLock")
    qdf.Parameters("GetLockValue").Value = LockValue
    qdf.Execute
    TrySetLock = qdf.RecordsAffected
End Function

Public Sub SetLock(LockValue As Integer)
    Do While TrySetLock(LockValue) = 0
    Loop
End Sub

这里是ReleaseLock Sub(它会通过传入的值释放锁定 - 即使没有这样的锁存在,这个Sub也会一直成功):

Public Sub ReleaseLock(LockValue As Integer)
    Dim dbs As dao.Database
    Dim qdf As dao.QueryDef
    Set dbs = CurrentDb
    Set qdf = dbs.QueryDefs("ReleaseLock")
    qdf.Parameters("GetLockValue").Value = LockValue
    qdf.Execute
End Sub

正如您在此处看到的,我使用了SQL和Microsoft Access表的主键属性的帮助来确保插入(或此处通过锁定引用)一次只能对一方或客户端成功,除非第一方移除(或释放)双方同意的锁定相同值的锁定,否则永远不会为另一方取得成功。

但是,如果一个客户端无法释放锁定(假设客户端的程序被冻结,并且不得不强制终止该程序),则会出现阻止依赖于同一锁定的所有客户端的问题。我想知道当程序被强制杀死时是否会调用类模块的析构函数?如果它被调用,那么我认为这个问题可以通过使一个带有某个值的锁类来修复,并且该类的destuctor将释放锁,而不必让其他客户端等待那个特定的锁。