Программная синхронизация доступа к данным

При одновременном доступе нескольких пользователей к одной и той же записи в источнике данных могут возникнуть конфликты. Например, конфликты могут возникать при выполнении метода Update или Delete объекта Recordset и метода OpenDatabase объекта Workspace или DBEngine. Предотвращение конфликтов зависит от настройки Access, касающейся методов блокировки записей, режима доступа к базе данных, периодов обновления данных. Об установке этих параметров мы уже говорили в разд. "Организация совместного доступа к данным и объектам" этой главы. Более подробную информацию можно найти в справочной системе Access.

При программном доступе к совместно используемым базам данных необходимо организовать собственную обработку ошибок, появляющихся при попытке выполнить операции, которые могут привести к возникновению конфликтов. В приложении "Игра в доминирование" используется метод блокировки на уровне записей, блокируются изменяемые записи. В этом случае при возникновении конфликта самым простым решением является ожидание момента, когда заблокированная запись будет освобождена другим пользователем. Этот подход достаточно просто реализовать в процедуре на VBA, используя оператор Resume для повторного выполнения действия через некоторый интервал времени (сделав паузу). Назовем этот способ синхронизацией доступа к данным.

Рассмотрим в качестве примера синхронизации функцию отправки сервером сообщения одному из игроков (программа 16.9). Вспомогательная функция doPause, позволяющая сделать паузу в работе приложения на заданное количество секунд, приведена в программе 16.10.

Программа 16.9. Синхронизация записи изменений в источнике данных

 ' Послать сообщение подключенному игроку Public Sub SendMessage(message As String, playerName As String) . ' Объявления локальных объектных переменных: Dim db As Database Dim rs As Recordset Dim counter As Integer ' Определяем собственную обработку ошибок: On Error GoTo errHandler Set db = CurrentDb ' Открываем таблицу сообщений для игрока: Set rs = db.OpenRecordset("Сообщения", dbOpenDynaset) On Error GoTo 0 ' Добавляем сообщение в таблицу сообщений клиента: rs.AddNew rs!ИмяИгрока = playerName rs!Сообщение = message ' Обработка ошибок, возникающих при совместном доступе ' к источнику данных: On Error GoTo tryAgain rs.Update On Error GoTo 0 rs.Bookmark = rs.LastModified ' Закрываем открытые объекты: closeAHHandler: rs.Close endHandler: ' Очищаем объектные переменные, т. к. они больше не используются: Set rs = Nothing Set db = Nothing ' Завершаем работу: Exit Sub ' Синхронизация: tryAgain: counter = counter + 1 If counter < 400 Then doPause 5 Resume End If Обработка ошибок: errHandler: Dim errMsg As String errMsg = "Ошибка: " & Err.Number & vbCrLf & _ "Источник: " & Err.Source & vbCrLf & _ vbCrLf & Err.Description MsgBox errMsg, vbCritical, ERR_TITLE Resume endHandler End Sub 

Программа 16.10. Сделать паузу на заданное количество секунд в работе приложения

 Public Sub doPause(seconds As Integer) Dim var_timeStart, var_timeCurrent Dim ftimeOut As Boolean var_timeStart = Time() ' Время начала паузы Do ' Передать управление другим процессам операционной системы DoEvents var_timeCurrent = Time() ' Текущее системное время ftimeOut = _ CDate(var timeCurrent - var timeStart) >= CDate(TimeSerial(0, 0, seconds)) Loop Until ftimeOut End Sub