2017-02-18 7 views
0

Я хотел бы знать, можно ли заблокировать таблицы базы данных одному пользователю за раз, чтобы выполнить терминологию ACID в базе данных и разрешить одну полную транзакцию в время в базе данных Microsoft Access с использованием VBA. В псевдокоде я ищу что-то вроде следующего:Заблокировать таблицы базы данных одному пользователю в Microsoft Access VBA

  • Заблокировать все таблицы (или определенные таблицы).
  • Выполнять все SQL или другие внутренние операции.
  • Выполните транзакцию и разблокируйте все таблицы (или определенные таблицы).

Но, в случае отказа клиента, например. клиентское приложение зависает, и пользователь должен принудительно закрыть его, пока клиентское приложение все еще обрабатывает транзакцию, оно вернет изменения и никогда не выполнит транзакцию и не разблокирует блокировку. Я ищу блокировку READ и WRITE, а клиент, который пытается заблокировать базу данных, когда она уже заблокирована, придется ждать, пока она не разблокируется?

+0

это начало того, что вы хотите http://stackoverflow.com/questions/5792169/opening-access-database-in-exclusive-mode#answer-5792773 –

ответ

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 
+0

Но это также не блокирует чтение. Я пробовал это раньше! – falhumai

+2

Вы должны были упомянуть о том, что в вашем вопросе, с учетом того, почему вы думаете, что это не решит вашу проблему. По-прежнему неясно, почему другие пользователи не должны иметь доступ на чтение во время выполнения транзакции. ACID (хотя Access не полностью соответствует ей) гарантирует, что в базе данных не будет несогласованного состояния: либо транзакция * успешно * завершена, либо вообще не выполнена. Между ними нет ничего. Одновременное чтение во время транзакции другого пользователя является центральной функцией, гарантируемой ACID. – Leviathan

+1

@ Левиафан прав. Невозможно заблокировать чтение, если пользователь имеет доступ к файлу. Чтение - это наименьший возможный уровень доступа. Доступ может быть заблокирован только в том случае, если пользователи не используют базу данных; первый пользователь может затем открыть файл исключительно (вы можете назвать его единственным режимом пользователя_). Тогда ни один другой пользователь не может открыть базу данных. Однако этого не может быть сделано в VBA - он управляется командной строкой. – Gustav

0

На самом деле, я нашел способ имитировать доступ одного пользователя для чтения и записи через тип взломанного блокировки. Ниже описано, как я это достиг.

Итак, я сделал небольшой стол в доступе, скажем, под названием 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 Таблицы доступа, чтобы убедиться, что вставка (или как указано здесь путем блокировки) может быть успешной только для одной стороны или клиента за раз, и никогда не будет успешной для другой стороны, если только первая сторона удаляет (или освобождает) блокировку того же значения блокировки, с которой согласны обе стороны.

Однако это может вызвать проблему блокировки ВСЕХ клиентов, полагающихся на одну и ту же блокировку, если один клиент не смог освободить блокировку (скажем, программа клиента заморожена и вынуждена была убить программу). Я хотел бы знать, будут ли вызваны деструкторы для модулей класса, когда программа будет убита или нет? Если он вызван, то я думаю, что эту проблему можно устранить, сделав класс блокировки с некоторым значением, а destuctor этого класса освободит блокировку и не заставит других клиентов ждать этой определенной блокировки.