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