Тверской государственный университет
Опубликован: 13.09.2006 | Доступ: свободный | Студентов: 5134 / 388 | Оценка: 4.23 / 3.83 | Длительность: 28:12:00
Специальности: Программист, Менеджер
Лекция 5:

Объекты ADO

Заметьте, число параметров в коллекции Parameters равно 2, а не 1, как должно было бы быть. Это связано с моей недоработкой и недоработкой Microsoft. Перед тем, как начать формировать коллекцию Parameters, я должен был очистить ее содержимое, вызвав метод Delete. Я не сделал этого, поскольку метод Delete не вызывается в данном контексте. По этой причине при повторном запуске процедуры произошло добавление параметра к уже имеющейся коллекции. В данном случае, когда выполняется запрос с одним параметром, это не приводит к ошибке, и я не стал усложнять уже и так довольно длинную процедуру. Но в принципе это серьезная ошибка, которая в другой ситуации может привести к неприятностям, например, если бы в следующей команде я попытался бы выполнить другой параметризованный запрос. Так что обратите внимание на эту ситуацию, и корректно работайте с коллекцией Parameters. Заметьте, проблемы исчезают для локально определенного объекта Command .

Объект Recordset

Этот объект представляет набор записей, возвращаемый в результате выполнения операции. В каждый момент можно работать только с одной выделенной записью набора, которая называется текущей записью. Естественно, есть методы, позволяющие перемещаться по записям набора. В предыдущем примере при работе с набором записей для этой цели использовались методы MoveFirst и MoveLast. При использовании ADO практически вся работа с данными ведется через этот объект. Он используется для того, чтобы читать записи из базы данных, изменять их содержимое, удалять и добавлять новые записи. Это самый сложный по своей организации объект ADO, - у него больше всего свойств, методов и событий. В предыдущем примере уже демонстрировалось применение этого объекта, где он создавался в результате выполнения команды, получающей результаты запроса к базе данных, затем полученные данные использовались для просмотра. Прежде чем обсудить все те возможности, которые предоставляет этот объект, давайте, как обычно, вначале рассмотрим его свойства, методы и события.

Свойства объекта Recordset

Объект Recordset имеет несколько десятков свойств. Попробуем разобраться в них:

  • Property AbsolutePage As PositionEnum, Property AbsolutePosition As PositionEnum, Property PageCount As Long, Property PageSize As Long, Property RecordCount As Long - группа свойств, определяющих нумерацию записей в наборе. Поскольку объект Recordset может определять достаточно большой набор записей, то, иногда целесообразно придать ему определенную структуру и выделить в нем страницы, на каждой из которых находится фиксированное число записей. Исключением является последняя страница, на которой записей, естественно, может быть меньше. Свойство PageSize определяет число записей на странице, по умолчанию значение этого свойства равно 10. Свойство PageCount задает число страниц, AbsolutePage - номер страницы, на которой расположена текущая запись набора. Значением этого свойства является целое в интервале от 1 до PageCount или значение из перечисления PositionEnum. Свойство RecordCount задает число записей в наборе, а свойство AbsolutePosition - порядковый номер записи, значением которого есть целое в интервале от 1 до RecordCount или одно из значений перечисления PositionEnum. Это перечисление содержит всего три значения: adPosBOF, adPosEOF, adPosUnknown, первые два из которых определяют позицию в начале и конце набора (перед первой и после последней записи набора), а третье значение задает неопределенную позицию. Заметьте, что пользоваться номерами записей для их идентификации следует с большой осторожностью, поскольку нумерация изменяется, когда в набор добавляются или из него удаляются записи. Для идентификации записей используются закладки, о которых будет сказано чуть ниже. Не все Провайдеры полностью поддерживают эти свойства.
  • Property ActiveCommand As Object, Property ActiveConnection As Variant. Свойства отражают связи между объектами ADO. Значением этих свойств является ссылка на объект Command, породивший набор записей и ссылка на соединение, при котором команда выполнялась. Если соединение закрыто, то выдается строка, описывающая соединение. Если набор записей создавался без явного выполнения команды, то возвращается ссылка на пустой объект Null.
  • Property BOF As Boolean, Property EOF As Boolean. Их имена пришли из соответствующих названий при работе с файлами - Begin Of File (BOF) и End Of File (EOF). Два булевых свойства, позволяющих определить достигнут ли конец набора записей при его последовательном просмотре в том или ином направлении. Вот пример двух классических схем прохода набора записей:
    Public Sub AllRecords()
    	'Две схемы прохода по набору записей
    	With Rst1
    		'Схема1: От начала к концу набора
    		.MoveFirst
    		Do While Not .EOF
    			'Обработка текущей записи
    			Debug.Print Rst1!Название
    			.MoveNext
    		Loop
    		'Схема2: От конца	к началу набора
    		.MoveLast
    		Do
    			'Обработка текущей записи
    			Debug.Print Rst1!Название
    			.MovePrevious
    		Loop Until .BOF
    	End With
    End Sub
    Я запустил на выполнение эту процедуру сразу по окончании работы процедуры CreateCommands из предыдущего примера и получил корректные результаты.
  • Property Bookmark As Variant. Часто в наборе записей необходимо иметь некоторое количество выделенных записей и периодически к ним обращаться. Как я уже говорил, номера записей для этой цели не годятся, поскольку они изменяются вместе с изменением самого набора. Для идентификации записей используются закладки, однозначно идентифицирующие запись при всех изменениях набора.

    Когда открывается набор записей, то все записи имеют уникальные закладки. Сохранение закладок - дело рук программиста. Вы можете сохранить закладку в собственной переменной типа Variant, используя значение свойства Bookmark. В тот момент, когда значение этой переменной будет присвоено свойству Bookmark набора записей, автоматически текущей станет запись с указанной закладкой. Вот пример, иллюстрирующий работу с закладками:

    Public Sub CreateBookmarks()
    	'Работа с закладкой
    	Dim MyBookmark As Variant
    	With Rst1
    		.MoveFirst
    		Do While Not .EOF
    			'Обработка текущей записи
    			If Rst1!Название = "Книжная лавка" Then
    				'Создаю закладку
    				MyBookmark = .Bookmark
    			End If
    			.MoveNext
    		Loop
    		'переход к записи с закладкой
    			.Bookmark = MyBookmark
    			Debug.Print Rst1!Название
    	End With
    End Sub
    Заметьте, по окончании цикла, текущая запись не определена, поскольку истинно свойство EOF, и это означает, что указатель сместился за последнюю запись. Но как только свойству Bookmark присвоено значение сохраненной закладки, текущей становится нужная нам запись.
  • Property CacheSize As Long. Я уже говорил, что основная работа с записями базы данных ведется во временной памяти, называемой буфером или кэшем. Несмотря на название, это свойство явно не задает размер памяти буфера. Оно должно быть целым значением в интервале от 1 до Maximum Open Rows. Правая граница интервала задается одноименным свойством из коллекции Properties объекта Recordset. Заметьте, значение 0 приводит к ошибке, по умолчанию значение свойства равно 1. Свойство позволяет указать число записей, помещаемых Провайдером в кэш при одном обращении. Заметьте, идет постоянный своппинг (обмен данными) в процессе работы, поскольку, когда достигнута последняя запись в буфере и нужна следующая запись, будет идти подкачка в буфер очередной порции. Значение свойства настраивается в течение жизни объекта Recordset.
О курсоре

Прежде чем продолжить рассмотрение свойств, есть смысл посвятить отдельный параграф курсору - важному понятию в модели ADO и при работе с базами данных. Курсор - это элемент базы данных, позволяющий управлять перемещением по записям, обновлением данных, видимостью изменений, сделанных другими пользователями.

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

Поскольку от решения вопросов, относящихся к курсорам, зависит эффективность работы с базой данных, и эти решения могут играть определяющую роль, то следует уметь правильно выбирать тип курсора, положение курсора и другие его характеристики. Тип курсора задает, как будет идти скроллинг, динамику изменения набора записей и многое другое. Положение курсора определяет, где будет идти основная работа с ним - на клиентской или серверной стороне. Рассмотрим возможные типы курсоров. Их четыре:

  • Forward Only - допускает перемещение по записям только вперед, не допуская полноценный скроллинг. Он обычно используется тогда, когда необходим только один проход по записям. Его можно использовать и в случаях нескольких проходов, закрывая и заново открывая курсор. После обработки очередной строки освобождаются ресурсы, связанные с ее хранением. По умолчанию этот курсор является динамическим, что означает, что он следит за всеми изменениями, сделанными другими пользователями в показываемых записях. Конечно, это не относится к уже просмотренным записям. Константа adOpenForwardOnly из перечисления CursorTypeEnum задает этот тип курсора.
  • Static - курсор этого типа в отличие от динамического не следит за изменениями, сделанными другими пользователями. Он сохраняет состояние набора записей на момент открытия. В зависимости от реализации статические курсоры могут допускать только чтение записей или возможность их обновления, могут допускать скроллинг или только перемещение вперед. Как правило, статический курсор допускает видимость изменений, сделанных самим приложением. Этот вид курсора обычно применяется, когда необходим скроллинг, но нет необходимости следить за изменениями, сделанными другими пользователями. Константа adOpenStatic задает этот тип курсора.
  • Keyset - курсор этого типа является, обычно, альтернативой курсору Forward Only. Он применяется, когда идет интенсивная работа с отдельными записями набора в произвольном порядке доступа к ним. Этот курсор называется курсором, управляемым набором ключей (keyset driven cursor). Для каждой строки из набора создается ключ, обеспечивающий быстрый доступ к любой строке набора.

    Что касается наблюдения за изменениями в наборе, то этот вид курсора обеспечивает стратегию, промежуточную между статическим и динамическим курсором. Он позволяет проследить за изменениями значений записей, сделанных другими пользователями, и этим он похож не динамический курсор. Но он не позволяет проследить за изменениями в составе набора - добавлению или удалению строк, изменения порядка их следования. При создании ключей состав набора замораживается. Когда запись удаляется из набора, то, поскольку ключ для нее сохраняется, то такая запись будет видна, как пустая запись - "дыра" в наборе. Добавляемые записи будут видны в виде добавлений в конец набора. Константа adOpenKeyset задает этот тип курсора.
  • Dynamic - динамический курсор обнаруживает все изменения, происходящие с набором записей, сделанные как самим приложением, так и всеми параллельно работающими пользователями. Все вставки, обновления или удаления, сделанные всеми пользователями видимы для этого типа курсора. Этот вид курсора выбирается, когда необходимо обеспечить совместную работу, но, нужно понимать, он требует от сервера больших затрат и при большом числе пользователей может существенно замедлить работу с набором данных. Константа adOpenDynamic задает этот тип курсора.

Поговорим теперь о такой важной характеристике курсора как его положение (Cursor Location). Константы adUseClient и adUseServer перечисления CursorLocationEnum задают положение курсора. В зависимости от установленного значения все необходимые ресурсы и сама работа с данными ведется на клиентской или серверной стороне. Достоинства работы на стороне клиента состоят в быстром отклике на обращение к записям, не требующим выхода в сеть. Когда работа с записями ведется в основном в режиме их чтения, то это положение курсора наиболее предпочтительно. Некоторым недостатком является то, что при больших наборах клиентскому компьютеру требуются большие ресурсы по памяти для хранения данных. Преимущества работы также теряются, когда интенсивно изменяется состав набора - записи удаляются, добавляются, так как эти изменения должны отражаться и на сервере. Если курсор расположен на серверной стороне, то объем передаваемых данных может быть существенно уменьшен, поскольку вся обработка ведется на сервере и клиенту передается только необходимые ему записи, а не весь набор. С другой стороны при большом числе активных пользователей каждому из них сервер должен выделить ресурсы, что может быть серьезной нагрузкой на сервер, с которой он может и не справиться. Еще одним недостатков курсора на серверной стороне является то, что в отличие от курсоров на клиентской стороне, не поддерживается работа в пакетном режиме (batch cursor), а возможна работа только с единственной записью.

Конечно, поддерживают работу на клиентской и серверной стороне разные библиотеки курсоров. При работе на стороне клиента для обеспечения работы с курсором ADO вызывает специальную службу - Microsoft Cursor Service for OLE DB, поддерживающую единую функциональность для различных Провайдеров.

Для того чтобы обеспечить целостность данных в СУБД имеются специальные механизмы, позволяющие временно закрыть доступ к записям базы другим пользователям, пока один из пользователей корректирует их содержание. С одной стороны, возможность закрытия доступа совершенно необходима в некоторых ситуациях, например, чтобы не продать один и тот же билет на самолет или поезд разным пассажирам. С другой стороны, когда, например, в интернете сотни тысяч пользователей обращаются одновременно к базе данных, то закрытие данных существенно снижает общую производительность системы. Система ADO позволяет указывать Провайдеру, какой тип закрытия данных следует применять при работе с объектами Recordset. Конкретный Провайдер может не поддерживать все типы закрытия, в этом случае он будет поддерживать возможный ближайший тип закрытия. Вернемся теперь к рассмотрению свойств объекта Recordset и продолжим это рассмотрение со свойств, связанных с курсором.

Ольга Гафарова
Ольга Гафарова

Добрый день. Подскажите формулы при решении задачи на рис. 2.2 в лекции №2. Закон Ома, какие должны использоваться формулы для I и R

Курс: Основы офисного программирования и документы Excel

Серегй Лушников
Серегй Лушников