Программная
синхронизация доступа к данным
При одновременном
доступе нескольких пользователей к одной и той же записи в источнике данных
могут возникнуть конфликты. Например, конфликты могут возникать при выполнении
метода 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