Компонента для подключения к mysql-серверам, не требует наличия никаких дополнительных библиотек кроме стандартных для Windows, работает со всеми серверами
В книге вы найдете множество нестандартных приемов программирования на языке Delphi, его недокументированные функции и возможности. Вы узнаете, как создавать маленькие шуточные программы. Большая часть книги посвящена программированию сетей, приведено множество полезных примеров. Для понимания изложенного не нужно глубоких знаний, даже начальных сведений о языке Delphi хватит для работы над каждой темой. Если вы ни разу не программировали, то на прилагаемом к книге компактдиске в каталоге вы найдете полную копию сайта автора и электронную версию его книги "Библия Delphi". Это поможет вам научится программировать без каких-либо начальных знаний. Прочитав книгу и дополнительную информацию, предоставленную на компакт-диске, вы можете пройти путь от начинающего программиста до продвинутого пользователя и познать хитрости хакеров и профессиональных программистов.
Книга, которая у вас в руках, — это введение в язык программирования C+ + . Она начинается с азов: от читателя не требуется каких-либо знаний в области программирования. В отличие от других книг по программированию па C+ + , в этой книге вопрос "почему'' считается не менее важным, чем вопрос "как". И поэтому перед изложением конкретных особенностей языка C + + читателю разъясняется, как они действуют в целом. Ведь каждая структурная особенность языка - это отдельный штрих единой картины. Прочитав книгу, вы сможете написать на C + + вразумительную программу и, что не менее важно, будете понимать, почему и как она работает. Книга рассчитана на пользователей с различным уровнем подготовки.
В книге вы найдете множество нестандартных приемов программирова-
ния на языке Delphi, его недокументированные функции и возможности.
Вы узнаете, как создавать маленькие шуточные программы. Большая часть книги посвящена программированию сетей, приведено множество полезных примеров. Для понимания изложенного не нужно глубоких знаний, даже начальных сведений о языке Delphi хватит для работы над каждой темой. Если вы ни разу не программировали, то на прилагаемом к книге компакт-диске в каталоге vr-online вы найдете полную копию сайта автора и электронную версию его книги "Библия Delphi". Это поможет вам научится программировать без каких-либо начальных знаний. Прочитав книгу и дополнительную информацию, предоставленную на компакт-диске, вы можете пройти путь от начинающего программиста до продвинутого пользователя и познать хитрости хакеров и профессиональных программистов.
В данном материале описываются практически все параметры, устанавливаемые в программе Setup BIOS фирмы AWARD Software International Inc. В конкретной материнской плате каких-то из описываемых параметров может и не быть. Одни и те же параметры могут называться по-разному в зависимости от производителя материнской платы, поэтому здесь в некоторых случаях приведено несколько вариантов.
Сегодня у нас под микроскопом исходник аудио плеера. Вернее сказать его серая заготовка из который, немного пофантазировав вы можете состряпать свой отличный аудио плеер на delphi.
Стоит отметить что в исходнике используется популярная delphi библиотека bass. Из возможностей плеера можно выделить такие как: возможность создания плей листа, перемотки, отображения время до окончания того или иного трека. Но и это еще не все в исходнике вы найдете регулятор громкости, регулятор баланса, есть эквалайзер и множество различных эффектов один из них например эхо.
Заключение: В общем если его привести в более красивый, аккуратный вид, поработать над дизайном программы то получиться довольно таки неплохой аудио плеер. Теперь задатки у вас есть, оасталось лишь чуточку поднапречся и доработать плеер. Жду ваших исходников)!
Установка: Исходник проверялся на Delphi 7 никаких проблем замеченно не было.
Библия хакера Максима Левина (2-е издание) Итак, опять про хакеров автора Максима Левина. Но теперь уже — «Библия». А почему именно библия?! Беда вся в том, что дело не в хакерах, так как знание каких-то там «принципов» еще не делает человека хакером. Это факт! Хотя бы потому, что необходимо еще много знать и уметь, чтобы получить признание в так называемых хакерских кругах. Поэтому «определитесь» с базовыми навыками, которые необходимо иметь хакеру, чтобы впоследствии стать виртуозом, но уже своего дела.
Книга `Настройка производительности UNIX-систем` отвечает на два важнейших вопроса: как добиться максимального эффекта без покупки дополнительного оборудования, и в каких случаях его все же стоит приобрести (больше памяти, более быстрые диски, процессоры и сетевые интерфейсы). Вложение денежных средств - не панацея. Адекватно оценить необходимость обновления и добиться максимальной производительности можно, только хорошо представляя работу компьютеров и сетей и понимая распределение нагрузки на системные ресурсы. Авторы книги оказали неоценимую помощь администраторам, подробно и аргументировано рассказав обо всех тонкостях искусства настройки систем. Полностью обновленное издание ориентировано на Solaris и Linux, но обсуждаемые принципы применимы к любым системам. В книге рассматриваются настройка параметров, управление рабочим процессом, методы измерения производительности, выявление перегруженных и неработоспособных участков сети, добавлен новый материал о дисковых массивах, микропроцессорах и оптимизации программного кода.
Что же такое CSS и как с ним бороться? На самом деле, бороться с ним не стоит, его необходимо изучать, дабы расширить свои возможности при создании красивого Web-сайта. Под термином CSS мы понимаем фразу "Каскадные Таблицы Стилей". Они внедряются в HTML-код и не требуют никаких специальных редакторов и компиляторов, ведь интерпретируются оные обычным броузером.
Прежде всего, микроконтроллер это процессор со всеми его "атрибутами", плюс встроенная, энергонезависимая память (программ и данных), что позволяет отказаться от внешней памяти программ и поместить программу в его энергонезависимую память.
Это позволяет создавать очень простые (в схемотехническом отношении) и компактные устройства, выполняющие, тем не менее, достаточно сложные функции. Иногда даже диву даешься: эта маленькая "штучка" заменяет целую "груду старого железа"
Любой микроконтроллер, по своим возможностям, конечно же, уступает процессору компьютера, но тем не менее, существует весьма обширный класс устройств, которые преимущественно реализуются именно на микроконтроллерах. И в самом деле, компьютер в карман не положишь и от батареек его не запитаешь. Поэтому, во многих случаях, микроконтроллерам просто нет альтернативы. "Сердцем" микроконтроллера является арифметико - логическое устройство (АЛУ).
Проще всего его представить в виде банального калькулятора, кнопками которого управляет программа, написанная на языке ассемблер (то есть, программист). Если вдуматься, то ничего особо сложного, в механизме управления такого рода калькулятором, нет. И в самом деле, если нужно, например, сложить числа А и В, то в тексте программы сначала задаются константы А и В, а затем дается команда "сложить". Программисту вовсе не обязательно знать, что происходит с нулями и единицами (разве только только для общего развития), ведь калькулятор он на то и калькулятор, чтобы избавить пользователя от "возни" с машинными кодами и прочими "неудобоваримостями".
Когда Вы работаете с компьютером, Вам и не нужно детально знать, что происходит в дебрях операционной системы.
Если Вы туда "полезете", то "с ума сойдете", а микроконтроллер, по своей сути, есть тот же самый компьютер, но только простой. Программисту только нужно детально знать, каким именно образом "приказать железяке" сделать то, что необходимо для достижения задуманного. Микроконтроллер можно представить себе как некий универсальный "набор" многофункциональных модулей (блоков), "рычаги управления" которыми находятся в руках программиста. Этих "рычагов" достаточно большое количество, и естественно, их нужно освоить и точно знать, что именно произойдет, если "дернуть" (дать команду на языке ассемблер) за тот или иной "рычаг". Вот здесь-то уже нужно знать, как "отче наше", каждую деталь и не жалеть на это "узнавание" времени. Только таким образом пустую "болванку" (незапрограммированый ПИК) можно "заставить"
выполнять какие-то "осмысленные" действия, результат большей части которых можно проверить в симуляторе MPLAB (об этом - позднее), даже не записывая программу в ПИК.
Итак, необходим переход к "модульному" мышлению. Любой микроконтроллер можно уподобить детскому конструктору, в состав которого входит множество всяких предметов, манипулируя с которыми, можно получить тот или иной конечный "продукт". Давайте с ними разберемся и "разложим все по полочкам". В качестве примера я буду использовать один из самых распространенных PIC контроллеров PIC16F84A. Он является как бы "проматерью" более сложных ПИКов, содержит минимальный "набор" модулей и как нельзя лучше подходит для первичного "въезда в м/контроллеры".
Энергонезависимая память.
Начнем с энергонезависимой памяти (память программ и память данных).
Информация, заложенная в энергонезависимую память, сохраняется при выключении питания, и поэтому именно в нее записывается программа.
То "место" энергонезависимой памяти, куда записывается программа, называется памятью программ. Объем памяти программ может быть различен. Для PIC16F84A, он составляет 1024 слова. Это означает, что он предназначен для работы с программами, объем которых не превышает 111024 слов.
Слово памяти программ не равно одному байту (8 бит), а больше его (14 бит). Отдельная команда, которую ПИК будет в дальнейшем выполнять, занимает одно слово в памяти программ. В зависимости от названия этой команды в ассемблере, слово принимает то или иное числовое значение в машинном коде. После записи в ПИК "прошивки" программы, слова памяти программ (машинные коды) как бы "превращаются" в команды, которые располагаются, в памяти программ, в том же порядке, в котором они следуют в исходном тексте программы, написанном на языке ассемблер, и в том же порядке им присваиваются адреса, при обращении к которым, та или иная команда "извлекается" из памяти программ для ее выполнения. Последовательность же их выполнения определяется логикой программы. Это означает то, что выполнение команд может происходить не в порядке последовательного возрастания их адресов, с шагом в одну позицию (так называемый инкремент), а "скачком". Дело в том, что только уж самые простейшие программы, в пределах одного их полного цикла, обходятся без этих "скачков", называемых переходами, и выполняются строго последовательно. В остальных же случаях, так называемая (мной) "рабочая точка программы" "мечется по тексту программы как угорелая" (как раз благодаря этим самым переходам).
Термин "рабочая точка программы" - моя "самодеятельность". В свое время, я был очень сильно удивлен отсутствием чего-то подобного в информации, связанной с объяснением работы программ. Казалось бы, чего проще, по аналогии, например, с рабочей точкой транзистора, сделать более комфортным "въезд в механику" работы программ? Так нет же, как будто специально, придумываются такие "головокружительные заменители", причем, в различных случаях, разные, что запутаться в этом очень просто. Итак, рабочую точку программы можно представить себе в виде некоего "шарика от пинг-понга", который "скачет" по командам текста программы в соответствии с алгоритмом (логикой) исполнения программы. На какую команду "шарик скакнул", та команда и исполняется. После этого он "перескакивает" на другую команду, она исполняется, и т.д. Эти "скачки" происходят непрерывно и в течение всего времени включения питания устройства (исполнения программы).
Любая более-менее сложная программа разбивается на части, которые выполняют отдельные функции (своего рода программки в программе) и которые называются подпрограммами. Атрибут любой подпрограммы - функциональная законченность производимых в ней действий.
По сути своей, эта "выдумка" введена в программирование для удобства реализации принципа "разделяй и властвуй": "врага" ведь гораздо легче "разгромить по частям, чем в общей массе". Да и порядка больше.
Безусловные переходы (переходы без условия) между подпрограммами (если они последовательно не переходят одна в другую), осуществляются при помощи команд безусловных переходов, в которых обязательно указывается адрес команды в памяти программ (косвенно - в виде названия подпрограммы или метки), на которую нужно перейти. Существуют также переходы с условием (условные переходы), то есть, с задействованием так называемого стека. Более подробно о переходах я расскажу позднее. Адреса команд определяются счетчиком команд (он называется PC). То есть, каждому состоянию счетчика команд соответствует одна из команд программы. Если команда простая, то счетчик просто инкрементируется (последовательно выполняется следующая команда), а если команда сложная (например, команда перехода или возврата), то счетчик команд изменяет свое состояние "скачком", активируя соответствующую команду.
Примечание: инкремент - увеличение на единицу величины числа, с которым производится эта операция, а декремент - уменьшение на единицу (так называемые комплиментарные операции). В простейшем случае, то есть в случае отсутствия в программе переходов, счетчик команд PC, начиная с команды "старта" (нулевой адрес), многократно инкрементируется, 12 последовательно активизируя все команды в памяти программ. Это означает, что в большинстве случаев, за каждый так называемый машинный цикл (такт работы программы: для ПИКов он равен четырем периодам тактового генератора) работы ПИКа, происходит исполнение одной команды. Есть и команды исполнение которых происходит за 2 машинных цикла (м.ц.), но их меньше. Команд, которые исполняются за 3 м.ц. и более нет. Таким вот образом, на большинстве участков программы (я их называю "линейными участками"), последовательно и перебираются адреса в памяти программ (команды последовательно исполняются).
В более сложных программах, с большим количеством условных и безусловных переходов, работу счетчика команд PC можно охарактеризовать фразой "Фигаро здесь, Фигаро там". 1 машинный цикл (м.ц.) равен 4-м периодам тактового генератора ПИКа. Следовательно, при использовании кварца на 4 Мгц., 1 м.ц.=1 мкс. Выполнение программы, в рабочем режиме (кроме работы в режиме пониженного энергопотребления SLEEP), никогда не останавливается, то есть, за каждый машинный цикл (или за 2, если команда исполняется за 2 м.ц.) должно выполняться какое-либо действие (команда). Тактовый генератор, формирующий машинные циклы, работает постоянно. Если его работу прервать, то исполнение программы прекратится.
Может сложиться ложное представление о том, что работу программы можно на какое-то время остановить, используя одну или несколько команд – "пустышек", не производящих полезных действий (есть такая команда NOP). Это представление не верно, так как в этом случае, речь идет только о задержке выполнения следующих команд, а не об остановке исполнения программы. Программа исполняется и в этом случае, так как "пустышка" есть та же самая команда программы, только не производящая никаких действий (короткая задержка). Если же нужно задержать выполнение каких-либо последующих команд на относительно длительное время, то применяются специальные, циклические подпрограммы задержек, о которых я расскажу позднее. Даже тогда, когда программа "зависает" ("глюк"), она исполняется, просто только не так, как нужно. Остановить (в буквальном смысле этого слова) исполнение программы можно только прекратив работу тактового генератора. Это происходит при переходе в режим пониженного энергопотребления (SLEEP), который используется в работе достаточно специфических устройств. Например, пультов дистанционного управления (и т.д.).
Отсюда следует вывод: программы, не использующие режим SLEEP (а таких - большинство), для обеспечения непрерывного выполнения команд программы, обязательно должны быть циклическими, то есть, иметь так называемый полный цикл программы, причем, многократно повторяющийся в течение всего времени включения питания. Проще говоря, рабочая точка программы должна непрерывно (не останавливаясь) "мотать кольца" полного цикла программы (непрерывно переходить с одного "кольца" на другое).
Общие выводы:
1. Команды программы "лежат" в памяти программ в порядке расположения команд в тексте программы.
2. Адреса этих команд находятся в счетчике команд PC и каждому адресу соответствует одна из команд программы.
3. Команда активируется (исполняется), если в счетчике команд находится ее адрес.
4. Активация команд происходит либо последовательно (на "линейном" участке программы), либо с переходом ("скачком") на другую команду (при выполнении команд переходов), с которой может начинаться как подпрограмма (переход на исполнение подпрограммы), так и группа команд, выделенная меткой (переход на исполнение группы команд, которой не присвоен "статус" подпрограммы).
5. Выполнение команд программы никогда не останавливается (за исключением режима SLEEP), и поэтому программа должна быть циклической.
Кроме памяти программ, PIC16F84A имеет энергонезависимую память данных (EEPROM память данных). Она предназначена для сохранения данных, имеющих место быть на момент выключения питания устройства, в целях их использования в дальнейшем (после следующего включения питания). Так же, как и память программ, память данных состоит из ячеек, в которых "лежат" слова. Слово памяти данных равно одному байту (8 бит). В PIC16F84A, объем памяти данных составляет 64 байта. Байты, хранящиеся в памяти данных, предназначены для их считывания в стандартные 8-битные регистры, речь о которых пойдет далее. Данные из этих регистров могут быть записаны в EEPROM память данных, то есть, может быть организован обмен данными между памятью данных и регистрами. Например, именно EEPROM память данных я использовал в своем частотомере для сохранения последних, перед выключением питания, настроек. Она же используется и для установки значений промежуточной частоты. Во многих программах, память данных вообще не используется, но это "вещь" исключительно полезная, и далее я расскажу о ней подробнее.
В данной статье приведены общие сведения об организации работы системы 1С:Предприятие с распределенной информационной базой (ИБ). Также описаны внутренние особенности организации механизма работы с распределенными данными для того, чтобы специалисты, осуществляющие конфигурирование и администрирование распределенных систем могли лучшее понимать выполняемые системой действия. Данная информация может также быть использована для оценки дополнительных затрат ресурсов системы, расходуемых на поддержание распределенной информационной базы.
Так как средства системы 1С:Предприятие для работы с распределенными информационными базами поставляются отдельно, сначала кратко остановимся на назначении и основных принципах организации работы системы 1С:Предприятие с территориально удаленными подразделениями.
Назначение и основные принципы
В тех случаях, когда предприятие представляет собой территориально распределенную структуру, зачастую сохраняется потребность в ведении единой системы учета. То есть необходимо иметь возможность работать в едином пространстве документов, получать отчеты, отражающие состояние дел как в территориально удаленных подразделениях предприятия, так и на предприятии в целом и т.п. При этом не всегда имеется возможность организовать работу всех подразделений с единой информационной базой в режиме он-лайн.
Для решения подобных задач предназначена компонента "Управление распределенными ИБ". С помощью указанной компоненты можно организовать двухуровневую структуру информационных баз (ИБ) системы 1С:Предприятие, состоящую из одной центральной и нескольких периферийных информационных баз, работающих с единой конфигурацией. При этом система будет стремиться поддерживать одинаковое состояние объектов данных во всех узлах распределенной ИБ.
Содержимое информационных баз синхронизируется путем переноса измененных объектов данных между каждой из периферийных и центральной ИБ. Для переноса данных используются так называемые файлы переноса данных. Перенос изменений выполняется только между центральной и периферийными ИБ. Перенос данных непосредственно между периферийными ИБ невозможен. Поэтому изменения данных, произведенные в одном из периферийных узлов распределенной ИБ попадают в другие периферийные узлы только через центральную ИБ.
В простейшем случае (по умолчанию) областью распространения изменений для всех объектов является вся распределенная ИБ. Таким образом, в случае если в течение какого-то времени изменения данных системы не будут производиться, и, в то же время, будут произведены все необходимые действия по обмену изменениями между узлами распределенной ИБ, то все узлы будут содержать абсолютно одинаковые данные.
В некоторых случаях может возникнуть необходимость в том, чтобы объекты того или иного типа никогда не попадали в те или иные узлы распределенной ИБ или никогда не покидали места своего создания. Для обеспечения такой возможности предназначен механизм настройки параметров миграции объектов. С его помощью можно ограничить распространение изменений объектов того или иного вида. Кроме того, в версии 7.7 системы 1С:Предприятие можно создавать периферийные ИБ, которые будут принимать информацию о измененных объектах из центральной ИБ, но не будут передавать изменения, сделанные в них самих.
Механизмы распространения изменений объектов работают полностью автоматически. Разработчик конфигурации лишен возможности вмешиваться в функционирование этих механизмов. Для того, чтобы механизмы распределенной ИБ начали работать, не нужно производить никаких специальных действий по конфигурированию системы.
Однако, для того, чтобы документы, элементы справочников и другие объекты, созданные в разных узлах распределенной ИБ, имели заведомо непересекающиеся пространства номеров, кодов и т. п., может потребоваться внести в конфигурацию некоторые изменения. Также изменения в конфигурации должны вноситься при необходимости обеспечить специальные ограничения работы пользователей на периферийных информационных базах.
Для переноса измененных объектов в распределенной ИБ и для первичного создания периферийной ИБ используется файл переноса данных. Он представляет собой упакованный (сжатый) файл, содержащий объекты информационной базы (все при создании периферийной ИБ или измененные при передаче изменений) в специальном формате. Формат данного файла не предназначен для использования его способами отличными от тех, которые предусмотрены механизмами выгрузки/загрузки и передачи изменений. Файл переноса фактически отражает содержимое объектов информационной базы в формате, не зависящем от формата базы данных. Это позволяет использовать в распределенной информационной системе в различных узлах различные форматы хранения данных, поддерживаемые системой 1С:Предприятие (DBF/CDX и MS SQL Server).
Регистрация изменений
Перенос измененных данных производится "пообъектно". То есть единицей переноса данных является так называемый ведущий объект. С точки зрения работы в распределенной информационной базе в 1С:Предприятии существуют следующие типы ведущих объектов:
константа,
элемент справочника,
документ,
календарь,
счет бухгалтерского учета,
типовая операция.
Вместе с документами переносятся все действия, выполняемые ими в процессе проведения: движения регистров, акты расчета, бухгалтерская операция, проводки. В случае, если при проведении документа производятся изменения периодических реквизитов элемента справочника, то производится перенос всего элемента справочника.
Регистрация изменений объектов производится автоматически при любом изменении объекта, независимо от того каким способом это изменение производилось (интерактивно или из встроенного языка). Кроме того в версии 7.7 системы 1С:Предприятие для таких объектов как элементы справочников и документы появилась возможность управления регистрацией изменений. Для этого у соответствующих объектов метаданных введен признак "Автоматическая регистрация изменений". Если этот признак установлен (значение по умолчанию), то автоматическая регистрация производится, а если признак сброшен, то регистрация не производится и изменения объектов в распределенной ИБ не распространяются. Но и в данном случае, при выполнении записи изменений объектов из встроенного языка можно управлять регистрацией изменений с помощью метода встроенного языка РегистрацияИзменений().
Регистрация изменений ведущих объектов производится в специальной служебной таблице. При этом фиксируются следующие данные об изменении объекта:
Сам ведущий объект;
Идентификатор той ИБ, в которую должно быть передано изменение;
Идентификатор ИБ, в которую должно быть передано изменение, служит для отслеживания переноса данных в каждую из ИБ, с которой данная ИБ обменивается данными. Таким образом, при изменении какого-либо объекта в центральной ИБ в таблицу будет помещено по одной записи для каждой из зарегистрированных периферийных информационных баз. Если же изменение объекта происходит в периферийной ИБ, то в таблицу будет занесена только одна запись, соответствующая центральной ИБ, так как каждая из периферийных ИБ непосредственно взаимодействует только с центральной.
Заметим, что удаление объекта является частным случаем изменения. Оно также помечается в таблице регистрации изменений и передается при выгрузке.
Выгрузка и загрузка изменений
Каждая выгрузка изменений осуществляется в адрес конкретной ИБ. В файл переноса, создаваемый при выгрузке попадают все объекты, записи об изменениях которых содержатся в таблице регистрации изменений для данной ИБ.
Заметим, что выгружаются не изменения объектов, а сами измененные объекты. То есть, если в документе изменилось значение одного реквизита, то будет передаваться весь документ и он будет полностью перезаписан на той ИБ, в которую переносится. Как уже отмечалось, вместе с документом будут перенесены и сделанные им движения регистров, операция и проводки. Если изменяется любой реквизит справочника, то передается полностью весь элемент. При этом история периодических реквизитов передается целиком. Последнее означает, что изменения сделанные в истории периодического реквизита элемента на в двух ИБ не будут сливаться вместе.
В процессе выгрузки в таблице регистрации изменений отмечается выгрузка изменений объектов.
При загрузке файла переноса данных помимо загрузки измененных данных выполняется так называемый прием подтверждений.
В случае, когда пришло подтверждение на получение выгрузки, содержащей последнее изменение объекта, запись об изменении удаляется из таблицы регистрации. То есть записи об изменении объектов данных хранятся в таблице регистрации до тех пор, пока не будет получено подтверждение о доставке измененного объекта по назначению.
Причем выгрузка измененного объекта будет производиться до тех пор, пока не будет получено подтверждение, о доставке изменения. Это значит, что если выполнять перенос все время в одном направлении и не выполнять обратного переноса то объем файла переноса данных будет все время расти, так как каждый раз будут передаваться все объекты, измененные после последнего полученного подтверждения.
При загрузке изменений объектов из периферийной ИБ в центральную, в таблицу регистрации изменений (если, конечно, параметры миграции настроены соответствующим образом) заносятся записи, указывающие, что загруженные из периферийной ИБ изменения объектов должны быть переданы в другие периферийные ИБ.
Изменения конфигурации
Как уже отмечалось, при работе с распределенной ИБ, конфигурация системы может быть изменена только в центральном узле.
Для регистрации изменений конфигурации и передачи ее на периферийные ИБ используется тот же механизм, что и для объектов данных. При записи измененной конфигурации, в таблицу регистрации изменений объектов по числу известных периферийных ИБ заносятся записи, фиксирующие факт изменения конфигурации.
После записи измененной конфигурации в распределенной ИБ складывается такая ситуация, что центральная и периферийные ИБ работают фактически с разными конфигурациями. В таком состоянии созданные на периферийной ИБ файлы переноса данных не могут быть загружены на центральной ИБ по той причине, что в условиях различных конфигураций содержащаяся в файле информация не может быть правильно интерпретирована. Обмен будет восстановлен только после того, как в периферийную ИБ будет загружена измененная конфигурация с центральной ИБ. То есть после изменения конфигурации требуется выполнить перенос из центральной ИБ в каждую из периферийных, а уже затем выполнять перенос из периферийных ИБ в центр.
Перенос измененной конфигурации в периферийные ИБ осуществляется тем же способом, что и перенос измененных объектов данных. В процессе очередной выгрузки из центральной ИБ, в файл переноса данных целиком включается измененная конфигурация, если, конечно, в таблице регистрации изменений содержится запись о том, что измененную конфигурацию следует передать в соответствующую периферийную ИБ. Выгрузка конфигурации также будет производиться до получения извещения о приеме измененной конфигурации.
Заметим, что конфигурация считается измененной при любых изменениях метаданных, форм, модулей, таблиц конфигурации, наборов прав, пользовательских интерфейсов, описаний. В состав конфигурации не входит список пользователей, а также внешние по отношению к файлу конфигурации (1CV7.MD) файлы (внешние отчеты, отдельно записанные таблицы и тексты). И эти внешние файлы не переносятся механизмом управления распределенной ИБ. Поэтому при конфигурировании распределенной системы не рекомендуется использовать в конфигурации находящиеся в отдельных файлах модули, таблицы и отчеты.
Для изменения уже работающей конфигурации можно рекомендовать использовать механизм загрузки измененной конфигурации. Он позволяет специалисту скопировать конфигурацию, выполнить в ней все необходимые изменения, отладить внесенные изменения (этот процесс может занять и несколько дней), а затем загрузить измененную конфигурацию в центральную ИБ, после чего изменения будут распространены на все периферийные ИБ с очередной передачей изменений. Такая последовательность позволит избежать многократной передачи измененной конфигурации в периферийные ИБ в процессе ее модернизации.
При загрузке файла переноса данных на периферийной ИБ, этап загрузки измененной конфигурации (если, конечно, она содержится в файле переноса данных) предшествует этапу загрузки измененных объектов данных. В случае неудачного завершения загрузки конфигурации, загрузка объектов данных производиться не будет и информационная база останется в том же состоянии, что и была до начала загрузки.
Загрузка измененной конфигурации может завершиться неудачей, если измененная конфигурация не соответствует существующим данным. Например, было уменьшено число уровней справочника, а новое число уровней оказывается меньшим, чем фактически содержащееся в справочнике или в других подобных случаях. Если такое произошло, то следует привести данные в соответствие с новой конфигурацией или изменить конфигурацию в центральной ИБ и заново произвести выгрузку, чтобы ликвидировать возникшее противоречие.
Коллизии
При работе в реальных распределенных ИБ один и тот же объект может изменяться одновременно в различных узлах распределенной ИБ. И при переносе измененных объектов из одной ИБ в другую может случиться так, что в какую-либо ИБ будет загружаться объект, зарегистрированный в самой этой ИБ как измененный. Такая ситуация носит название коллизии. Приведем описание действий системы в наиболее типовых вариантах коллизий.
Один и тот же объект изменен более чем в одной ИБ.
Общий принцип здесь состоит в том, что "главным" считается изменение, произведенное в центральной ИБ. Отработка ситуации различается в зависимости от того, на какой ИБ - центральной или периферийной коллизия обнаружена. Если коллизия обнаружена на центральной ИБ, то есть при загрузке файла переноса из периферийной ИБ обнаружено, что один из измененных объектов также изменен и в центральной ИБ, то изменения объекта в центральную ИБ не загружаются. При этом гарантируется, что при очередной выгрузке в адрес периферийной ИБ будет передано состояние объекта как оно есть в центральной ИБ. Если же коллизия обнаружена на периферийной ИБ, то изменения объекта, прибывшие из центральной ИБ загружаются.
Объект, измененный в одной ИБ, удален в другой.
В данном случае принцип заключается в том, что изменение всегда "главнее" удаления. В случае, если на центральную ИБ прибывает файл переноса, в котором содержится информация, что некоторый объект удален на периферийной ИБ, то в центральной ИБ объект не удаляется, а в записи таблицы регистрации изменений данный объект помечается как измененный. То есть при очередном обмене объект будет восстановлен в той ИБ, в которой он был удален, причем само содержание объекта будет соответствовать той ИБ, которая "отвергла" удаление.
Аналогичные действия производятся, если коллизия обнаружена на периферийной ИБ.
Объект, удаленный в одной ИБ, не может быть удален в другой по причине наличия ссылок на него.
При загрузке изменений, если загружается информация об удалении объектов, автоматически включается механизм контроля ссылочной целостности и выполняется проверка наличия ссылок в данной ИБ на объекты, которые переданы как удаленные.
В случае обнаружения коллизии такого рода, вне зависимости от того на какой из ИБ она была обнаружена, выполняется следующее: удаление не выполняется, а в таблицу регистрации изменений заносится запись о том, что объект должен быть перенесен в адрес той ИБ, из которой была прислана информация о его удалении.
При очередном обмене объект восстанавливается в той ИБ, в которой он был удален, однако само содержание объекта будет соответствовать той ИБ, которая "отвергла" удаление.
Таким образом, управление распределенной информационной базой имеет определенную стратегию автоматического разрешения любых коллизий с описанными приоритетами. Однако, в реальных условиях рекомендуется средствами конфигурации определить возможные действия пользователей на различных узлах таким образом, чтобы исключить или минимизировать вероятность возникновения коллизий. Основным путем является определения средствами конфигурации "ответственного" узла за каждый ведущий объект в распределенной ИБ и ограничение всем остальным возможности его редактирования и удаления. Определение "ответственных" должно происходить исходя из логики работы предприятия. Очевидно, что многие виды объектов можно разрешить изменять только в центральной ИБ (например, список складов). Для многих объектов можно рекомендовать средствами встроенного языка установить возможность изменения только на той ИБ, на которой они созданы, например для документов.
Параметры миграции
С помощью настройки параметров миграции можно ограничивать области распространения изменений объектов. Настройка параметров миграции происходит по видам "ведущих" объектов. То есть для каждого вида "ведущих" объектов можно определить конкретную настройку параметров миграции. В настройке параметров миграции объектов ведущую роль играет выбор того или иного варианта области распространения изменений объектов данного вида. Существуют три варианта настройки области распространения:
Все информационные базы. Данный вариант настройки используется по умолчанию для всех объектов. В этом случае любые изменения объектов данного типа будут распространяться по всем узлам распределенной ИБ. Этот вариант обеспечивает полную синхронизацию объектов данного вида во всей распределенной ИБ. Очевидно, что этот вариант наиболее прост для конфигурирования.
Место создания. Данный вариант настройки также является довольно простым. В этом случае изменения объекта не передаются в другие ИБ. При такой настройке параметров миграции, объект данного вида никогда не "покидает" места своего создания и не появляется в других ИБ. Однако при выборе данного варианта следует учитывать возможные ссылки на объекты данного вида из объектов других видов, имеющих другие параметры миграции. Например, если установить такой вариант для справочника, и в документах, которые участвуют в обмене, будет содержаться реквизит типа справочник данного вида, то при переносе документа получится неразрешенная ссылка.
Место создания и центр. При таком варианте настройки области распространения объектов существенную роль играет понятие места создания объекта. Местом создания объекта считается ИБ, в которой был создан конкретный объект. Естественно, что различные объекты одного вида могут быть созданы в различных ИБ. Однако место создания объекта может быть определено не для всех видов "ведущих" объектов. Для таких объектов как константы, календари или корректные проводки место создания не определено. Поэтому для этих видов объектов вариант настройки "Место создания и центр" не может быть установлен.
В случае выбора такого варианта области распространения, объекты данного вида помимо места их создания попадают еще и на центральную ИБ. То есть, в случае, если для некоторого вида объектов установлена область распространения "Место создания и центр", то для объектов этого вида, созданных на периферийной ИБ, их изменения будут передаваться между местом их создания и центральной ИБ. Для объектов того же вида, созданных на центральной ИБ, изменения не будут передаваться никуда. С помощью такого варианта области распространения можно добиться такого эффекта, что все объекты того или иного вида будут "собираться" на центральной ИБ, а на любой из периферийных ИБ будут находиться только те объекты, для которых она является местом создания.
В случае выбора области распространения "Место создания и центр", для вида объекта можно задать перечень периферийных узлов распределенной ИБ, которые дополнительно включаются в область распространения всех объектов данного вида. Этот перечень задается как список кодов периферийных ИБ, разделенный запятыми. При задании кодов ИБ допускается использование символов-заменителей '*'. Символ-заменитель должен завершать последовательность символов, образующих код одной или нескольких периферийных ИБ. Таким образом, "A*" представляет собой обозначение всех периферийных ИБ, коды которых начинаются символом 'А'. Последовательность "A*B" является ошибочной, так как символ '*' не завершает последовательность символов, представляющих код периферийной ИБ.
Кроме того, как отмечалось выше, дополнительной возможностью управлять распространением изменений объектов в версии 7.7 системы 1С:Предприятие является особый вид периферийных ИБ, которые получают изменения из центральной ИБ, а сами информацию о сделанных в них изменениях не передают. Для создания периферийной ИБ такого рода, надо при ее инициализации указать признак "Только получатель".
Отдельно стоит рассмотреть случай, когда параметры миграции объектов изменяются в процессе изменения конфигурации уже работающей системы. Изменения параметров миграции для каждого из объектов производится независимо от других. То есть, Конфигуратор не отслеживает ссылки между объектами при настройке параметров миграции. Таким образом, при определенных вариантах настройки параметров миграции у некоторых объектов могут появиться ссылки, указывающие "никуда". Ответственность за сохранение ссылочной целостности в распределенных ИБ возлагается на лицо, занимающееся конфигурированием системы. Общим правилом настройки параметров миграции является определение области миграции для конкретного вида объектов равной более широкой, чем область миграции ссылающихся на него объектов. Например, для справочника область миграции должна быть определена не уже, чем области миграции документов и справочников, в которых есть реквизиты типа "справочник" данного вида. Если, например, измерение регистра имеет тип "справочник" данного вида, то область миграции справочника должна покрывать области миграции всех документов, которые могут записать движения данного регистра.
При изменении параметров миграции того или иного объекта система старается привести имеющиеся данные в соответствие с новыми параметрами. Общим принципом здесь является то, что при изменении параметров миграции объекты никогда ни в каком узле распределенной ИБ не удаляются. Даже в том случае, если в соответствии с вновь установленными параметрами миграции их там быть не должно. Изменения производятся лишь в таблице регистрации изменений. Рассмотрим случаи изменения параметров миграции объектов подробнее.
Наиболее простой случай - это смена любого из вариантов области распространения на вариант "Место создания". В этом случае из таблицы регистрации изменений удаляются все записи по данному виду объектов. То есть все изменения объектов, еще не переданные в другие ИБ, не будут переданы. При этом, все объекты для которых данная ИБ не является местом создания, не будут удалены. Просто их изменения (как и изменения других объектов данного вида) не будут больше передаваться в другие ИБ.
Следующий случай - это смена области распространения "Место создания" на варианты "Все информационные базы" или "Место создания и центр". В этом случае в таблицу регистрации изменений заносятся записи для передачи всех объектов, для которых текущая ИБ является местом создания во все ИБ, в которые должны передаваться изменения в соответствии с вновь заданной настройкой. В случае, если такая смена производится для объектов, для которых место создания не определено (константы, календари, корректные проводки), то записи в таблицу регистрации изменений будут произведены только в центральной ИБ. Этими двумя вариантами и ограничиваются возможные случаи изменения параметров миграции для такого рода объектов. Все остальные случаи возможны только для тех объектов, для которых место создания можно определить.
При изменении области распространения объектов с "Место создания и центр" на "Все информационные базы", какие-либо действия предпринимаются только в центральной ИБ. В этом случае определяется список периферийных ИБ, попавших в список дополнительно включаемых в область распространения, но ранее в него не входивших. После этого производится обход всех объектов данного вида и для каждого из объектов в таблицу регистрации изменений вносятся записи для передачи состояния объекта в каждую из попавших в список периферийных ИБ, за исключением ИБ места создания объекта.
Последний и самый сложный случай - это изменение области распространения объектов с "Все информационные базы" на "Место создания и центр" или изменение списка дополнительных ИБ в варианте "Место создания и центр". Действия, производимые в данном случае различаются в зависимости от того, производятся они в центральной ИБ или в периферийной. В центральной ИБ для каждой из периферийных ИБ, не попавших в новый перечень дополнительно включаемых в область распространения, выполняется удаление из таблицы регистрации изменений записей соответствующих данному виду объектов, но только для тех объектов, для которых эта периферийная ИБ не является местом создания. Затем определяется список периферийных ИБ, попавших в список дополнительно включаемых в область распространения, но ранее в него не входивших. Естественно, что в случае, если предыдущим вариантом настройки области распространения было "Все информационные базы", то этот список окажется пустым. Затем, как и в предыдущем случае, производится обход всех объектов данного вида и для каждого из объектов в таблицу регистрации изменений вносятся записи для передачи объекта в каждую из попавших в список периферийных ИБ, за исключением ИБ места создания объекта.
Проблемы конфигурирования и администрирования
При разработке конфигурации для распределенной ИБ проявляется ряд объективно существующих проблем, которые решаются как средствами конфигурации, так и административными решениями.
Очевидной проблемой, которая уже упоминалась выше, является уникальная и последовательная нумерация документов и элементов справочников. Для организации уникальной нумерации используется механизм префиксов. Для его включения в конфигурацию, прежде всего, следует выработать некоторую дисциплину, зависимости префикса от ИБ, в которой создается объект. В простейшем случае это может быть собственно код ИБ. Однако часто префикс может автоматически определяться на каждой ИБ, но не являться ее кодом, так как он может участвовать в печатных формах документов и должен быть понятным для пользователей системы. Более сложной задачей является обеспечение сквозной нумерации объектов без префиксов в случае, когда такая нумерация регламентируется нормативными документами. Особенно сложным является обеспечение строго последовательной нумерации. Очевидно, что полного решения данной проблемы не может быть в принципе, так как объекты создаваемые динамически в независимых системах не могут иметь строгой сквозной нумерации. Отчасти данная проблема решается с помощью введения диапазонов номеров, выделяемых для каждой ИБ. Следует заметить, что номера документов и коды справочников не являются внутренними идентификаторами и их уникальность для системы не обязательна. Это значит, что поддержку уникальность номеров и кодов можно отключить для тех видов, объектов, для которых она не нужна. Кроме того, средствами конфигурации можно организовать перенумерацию объектов, например в центральной ИБ. Однако следует иметь ввиду, что эти изменения будут передаваться как и любые другие изменения, что может вызвать достаточно большой объем передаваемых между узлами данных.
Более сложной проблемой является ситуация, когда возникает необходимость использования некоторого нового объекта в двух и более узлах одновременно, до осуществления передачи данных. Например, новый товар должен быть введен и на центральной ИБ и на периферийной. Важно понимать, что созданный ведущий объект системы 1С:Предприятие обладает некоторой сущностью - внутренним идентификатором, который уникален во всей распределенной системе. То есть один и тот же объект не может быть введен в двух узлах. Даже при полном соответствии кодов, номеров и всех данных это будут два разных объекта. Такой принцип необходим для четкой работы системы со всех точек зрения.
Заметим, что возможные варианты ввода двух объектов и затем автоматической замены на центральной ИБ всех ссылок на один из объектов, достаточно сложны в реализации и весьма ненадежны.
Поэтому, на наш взгляд, решение проблемы должно лежать в области администрирования системы. Технология работы пользователей должна быть построена таким образом, чтобы ввод объекта производился на одном узле.
В отдельных случаях может использоваться следующее решение. В справочник заранее вносится некоторое количество новых элементов со специальными кодами или в специальную группу. При появлении необходимости ввода нового товара реально не вводится новый элемент, а изменяется один этих элементов. При этом административными силами должно быть обеспечено идентичное изменение одного и того же "зарезервированного" объекта в тех узлах распределенной ИБ, в которой он должен быть использован до обмена данными. При обмене данными сами реквизиты элемента будут системой синхронизированы, а ссылки в других объектах, разумеется будут идентичными, так как использовался один и тот же объект.
В любых случаях следует учитывать, что раздельный ввод и использование объектов потребует от пользователей правильного ввода данных. Так, например, при вводе нового товара в двух узлах с разными ценами могут иметь место серьезные ошибки в оформлении документов.
Еще одна проблема, с которой приходится сталкиваться при конфигурировании распределенной ИБ, это правильное поддержание механизмов учета компонент при неполной миграции объектов. Следует учитывать, что итоги оперативного и бухгалтерского учета не являются самостоятельными объектами. Они не переносятся, а рассчитываются на основании перенесенных движений регистров и проводок. Движения регистров и проводки переносятся соответственно только вместе с документами. Таким образом, для правильного состояния итогов на некоторой ИБ, на нее должны переноситься все документы, осуществляющие движения регистров или записывающие проводки влияющие на эти итоги. С другой стороны, это не означает, что переноситься должны все документы, записывающие движения конкретного регистра и проводки. Например, если на периферийной ИБ вводятся документы, выполняющие движения по одному складу, и итоги регистра учета товарного запаса в данной ИБ нужны только по данному складу, то, разумеется, в данном узле будет достаточно наличия всех документов выполняющих движения регистров по данному складу. Это достигается установкой параметра миграции "Место создания и центр".
Данная статья предназначена для начинающих программистов, которые никогда не работали с потоками, и хотели бы узнать основы работы с ними. Желательно, чтоб читатель знал основы ООП и имел какой-нибудь опыт работы в Delphi.
Для начала давайте определимся, что под словом "поток" я подразумеваю именно Thread, который еще имеет название "нить". Нередко встречал на форумах мнения, что потоки не нужны вообще, любую программу можно написать так, что она будет замечательно работать и без них. Конечно, если не делать ничего серьёзней "Hello World" это так и есть, но если постепенно набирать опыт, рано или поздно любой начинающий программист упрётся в возможности "плоского" кода, возникнет необходимость распараллелить задачи. А некоторые задачи вообще нельзя реализовать без использования потоков, например работа с сокетами, COM-портом, длительное ожидание каких-либо событий, и т.д.
Всем известно, что Windows система многозадачная. Попросту говоря, это означает, что несколько программ могут работать одновременно под управлением ОС. Все мы открывали диспетчер задач и видели список процессов. Процесс - это экземпляр выполняемого приложения. На самом деле сам по себе он ничего не выполняет, он создаётся при запуске приложения, содержит в себе служебную информацию, через которую система с ним работает, так же ему выделяется необходимая память под код и данные. Для того, чтобы программа заработала, в нём создаётся поток. Любой процесс содержит в себе хотя бы один поток, и именно он отвечает за выполнение кода и получает на это процессорное время. Этим и достигается мнимая параллельность работы программ, или, как её еще называют, псевдопараллельность. Почему мнимая? Да потому, что реально процессор в каждый момент времени может выполнять только один участок кода. Windows раздаёт процессорное время всем потокам в системе по очереди, тем самым создаётся впечатление, что они работают одновременно. Реально работающие параллельно потоки могут быть только на машинах с двумя и более процессорами.
Для создания дополнительных потоков в Delphi существует базовый класс TThread, от него мы и будем наследоваться при реализации своих потоков. Для того, чтобы создать "скелет" нового класса, можно выбрать в меню File - New - Thread Object, Delphi создаст новый модуль с заготовкой этого класса. Я же для наглядности опишу его в модуле формы. Как видите, в этой заготовке добавлен один метод - Execute. Именно его нам и нужно переопределить, код внутри него и будет работать в отдельном потоке. И так, попробуем написать пример - запустим в потоке бесконечный цикл:
Запустите пример на выполнение и нажмите кнопку. Вроде ничего не происходит - форма не зависла, реагирует на перемещения. На самом деле это не так - откройте диспетчер задач и вы увидите, что процессор загружен по-полной. Сейчас в процессе вашего приложения работает два потока - один был создан изначально, при запуске приложения. Второй, который так грузит процессор - мы создали по нажатию кнопки. Итак, давайте разберём, что же означает код в Button1Click:
тут мы создали экземпляр класса TNewThread. Конструктор Create имеет всего один параметр - CreateSuspended типа boolean, который указывает, запустить новый поток сразу после создания (если false), или дождаться команды (если true).
свойство FreeOnTerminate определяет, что поток после выполнения автоматически завершится, объект будет уничтожен, и нам не придётся его уничтожать вручную. В нашем примере это не имеет значения, так как сам по себе он никогда не завершится, но понадобится в следующих примерах.
Свойство Priority, если вы еще не догадались из названия, устанавливает приоритет потока. Да да, каждый поток в системе имеет свой приоритет. Если процессорного времени не хватает, система начинает распределять его согласно приоритетам потоков. Свойство Priority может принимать следующие значения:
tpTimeCritical - критический
tpHighest - очень высокий
tpHigher - высокий
tpNormal - средний
tpLower - низкий
tpLowest - очень низкий
tpIdle - поток работает во время простоя системы
Ставить высокие приоритеты потокам не стоит, если этого не требует задача, так как это сильно нагружает систему.
Ну и собственно, запуск потока.
Думаю, теперь вам понятно, как создаются потоки. Заметьте, ничего сложного. Но не всё так просто. Казалось бы - пишем любой код внутри метода Execute и всё, а нет, потоки имеют одно неприятное свойство - они ничего не знают друг о друге. И что такого? - спросите вы. А вот что: допустим, вы пытаетесь из другого потока изменить свойство какого-нибудь компонента на форме. Как известно, VCL однопоточна, весь код внутри приложения выполняется последовательно. Допустим, в процессе работы изменились какие-то данные внутри классов VCL, система отбирает время у основного потока, передаёт по кругу остальным потокам и возвращает обратно, при этом выполнение кода продолжается с того места, где приостановилось. Если мы из своего потока что-то меняем, к примеру, на форме, задействуется много механизмов внутри VCL (напомню, выполнение основного потока пока "приостановлено"), соответственно за это время успеют измениться какие-либо данные. И тут вдруг время снова отдаётся основному потоку, он спокойно продолжает своё выполнение, но данные уже изменены! К чему это может привести - предугадать нельзя. Вы можете проверить это тысячу раз, и ничего не произойдёт, а на тысяча первый программа рухнет. И это относится не только к взаимодействию дополнительных потоков с главным, но и к взаимодействию потоков между собой. Писать такие ненадёжные программы конечно нельзя.
Синхронизации потоков
Если вы создали шаблон класса автоматически, то, наверное, заметили комментарий, который дружелюбная Delphi поместила в новый модуль. Он гласит: "Methods and properties of objects in visual components can only be used in a method called using Synchronize". Это значит, что обращение к визуальным компонентам возможно только путём вызова процедуры Synchronize. Давайте рассмотрим пример, но теперь наш поток не будет разогревать процессор впустую, а будет делать что-нибудь полезное, к примеру, прокручивать ProgressBar на форме. В качестве параметра в процедуру Synchronize передаётся метод нашего потока, но сам он передаётся без параметров. Параметры можно передать, добавив поля нужного типа в описание нашего класса. У нас будет одно поле - тот самый прогресс:
Вот теперь ProgressBar двигается, и это вполне безопасно. А безопасно вот почему: процедура Synchronize на время приостанавливает выполнение нашего потока, и передаёт управление главному потоку, т.е. SetProgress выполняется в главном потоке. Это нужно запомнить, потому что некоторые допускают ошибки, выполняя внутри Synchronize длительную работу, при этом, что очевидно, форма зависает на длительное время. Поэтому используйте Synchronize для вывода информации - то самое двигание прогресса, обновления заголовков компонентов и т.д.
Вы наверное заметили, что внутри цикла мы используем процедуру Sleep. В однопоточном приложении Sleep используется редко, а вот в потоках его использовать очень удобно. Пример - бесконечный цикл, пока не выполнится какое-нибудь условие. Если не вставить туда Sleep мы будем просто нагружать систему бесполезной работой.
Надеюсь, вы поняли как работает Synchronize. Но есть еще один довольно удобный способ передать информацию форме - посылка сообщения. Давайте рассмотрим и его. Для этого объявим константу:
В объявление класса формы добавим новый метод, а затем и его реализацию:
Используя функцию SendMessage, мы посылаем окну приложения сообщение, один из параметров которого содержит нужный нам прогресс. Сообщение становится в очередь, и согласно этой очереди будет обработано главным потоком, где и выполнится метод SetProgressPos. Но тут есть один нюанс: SendMessage, как и в случае с Synchronize, приостановит выполнение нашего потока, пока основной поток не обработает сообщение. Если использовать PostMessage этого не произойдёт, наш поток отправит сообщение и продолжит свою работу, а уж когда оно там обработается - неважно. Какую из этих функций использовать - решать вам, всё зависит от задачи.
Вот, в принципе, мы и рассмотрели основные способы работы с компонентами VCL из потоков. А как быть, если в нашей программе не один новый поток, а несколько? И нужно организовать работу с одними и теми же данными? Тут нам на помощь приходят другие способы синхронизации. Один из них мы и рассмотрим. Для его реализации нужно добавить в проект модуль SyncObjs.
Критические секции
Работают они следующим образом: внутри критической секции может работать только один поток, другие ждут его завершения. Чтобы лучше понять, везде приводят сравнение с узкой трубой: представьте, с одной стороны "толпятся" потоки, но в трубу может "пролезть" только один, а когда он "пролезет" - начнёт движение второй, и так по порядку. Еще проще понять это на примере и тем же ProgressBar'ом. Итак, запустите один из примеров, приведённых ранее. Нажмите на кнопку, подождите несколько секунд, а затем нажмите еще раз. Что происходит? ProgressBar начал прыгать. Прыгает потому, что у нас работает не один поток, а два, и каждый из них передаёт разные значения прогресса. Теперь немного переделаем код, в событии onCreate формы создадим критическую секцию:
У TCriticalSection есть два нужных нам метода, Enter и Leave, соответственно вход и выход из неё. Поместим наш код в критическую секцию:
Попробуйте запустить приложение и нажать несколько раз на кнопку, а потом посчитайте, сколько раз пройдёт прогресс. Понятно, в чем суть? Первый раз, нажимая на кнопку, мы создаём поток, он занимает критическую секцию и начинает работу. Нажимаем второй - создаётся второй поток, но критическая секция занята, и он ждёт, пока её не освободит первый. Третий, четвёртый - все пройдут только по-очереди.
Критические секции удобно использовать при обработке одних и тех же данных (списков, массивов) разными потоками. Поняв, как они работают, вы всегда найдёте им применение.
В этой небольшой статье рассмотрены не все способы синхронизации, есть еще события (TEvent), а так же объекты системы, такие как мьютексы (Mutex), семафоры (Semaphore), но они больше подходят для взаимодействия между приложениями. Остальное, что касается использования класса TThread, вы можете узнать самостоятельно, в help'е всё довольно подробно описано. Цель этой статьи - показать начинающим, что не всё так сложно и страшно, главное разобраться, что есть что. И побольше практики - самое главное опыт!
Вторая часть серии статей "Использование регулярных выражений в PHP" посвящена решению ряда проблем обработки сложных текстов с помощью "продвинутых" операторов регулярных выражений.
Несмотря на то, что термины данные и информация используются взаимозаменяемо, между ними есть существенная разница. Данные существуют реально. Данные — - это список температур, перечень недавних продаж или опись товара, имеющегося в наличии. Информация — это прогнозы. Информация — это предсказание погоды, прогноз прибылей и убытков и тенденции сбыта. Данные записываются в виде нулей и единиц, в то время как информация обрабатывается мозгом.
Между данными и информацией располагается приложение: механизм, который преобразует одно в другое и наоборот. Например, при покупке книги в Интернете это приложение преобразует вашу информацию — название книги, идентификатор, информацию о банковском счете — в данные: номер заказа, цену со скидкой, характеристики транзакции с использованием кредитной карточки и количество оставшихся в наличии экземпляров книги. Аналогичным образом, приложение преобразует данные в запрос на выборку со склада, отметку об отгрузке и номер отслеживания — информацию, необходимую для реализации продажи.
В действительности сложность создания приложения прямо пропорциональна преобразованиям, которые оно выполняет. Гостевая книга Web-сайта, передающая имя и адрес в поля базы данных, устроена элементарно. С другой стороны, онлайновый магазин, который передает большое количество видов информации в модель данных коммерческой сделки и преобразует данные в информацию для реализации процесса принятия решений, достаточно сложен с точки зрения разработки. Искусство программирования заключается в умелом манипулировании данными и информацией — мастерство, схожее с фиксацией света в живописи.
Как было сказано в первой части, регулярные выражения являются одним из самых мощных средств манипулирования данными. Регулярные выражения лаконично описывают форму данных и раскладывают их на составляющие. Например, следующее регулярное выражение можно использовать для обработки температуры, заданной в градусах по Цельсию или по Фаренгейту: /^([+-]?[0-9]+)([CF])$/.
Регулярное выражение сравнивает начало строки (отображается знаком "крышка" (^), за которым идет знак "+", знак "-", или ничего ([+-]?), за которым следует целое число ([0-9]+), обозначение шкалы — Цельсия или Фаренгейта ([CF]) — и заканчивается концом строки (обозначается знаком доллара $).
В данном регулярном выражении операторы начала строки и конца строки представляют собой примеры операторов нулевой ширины или совпадений по положению, а не по символам. Круглые скобки также не указывают на символы. Зато, если заключить шаблон в круглые скобки, то будет извлечен текст, соответствующий шаблону. Следовательно, если текст полностью сопоставим с шаблоном, то первая пара круглых скобок выдаст строку, представляющую собой положительное или отрицательное целое число, например, +49, а вторая пара круглых скобок - или букву C, или F.
В первой части серии представлено понятие регулярного выражения и были описаны PHP-функции для сравнения текста с шаблонами, а также для извлечения совпадений. А теперь давайте углубимся в изучение регулярных выражений и посмотрим на некоторые "продвинутые" операторы и средства.
Круглые скобки опять приходят на помощь
В большинстве случаев пара круглых скобок используется для описания части шаблона и получения текста, соответствующего этой части. Однако от круглых скобок не всегда требуется получение части шаблона. Как и в сложной арифметической формуле, круглые скобки можно использовать для группировки условий.
Приведу пример. Догадаетесь, какому типу данных соответствует данное выражение?
/[-a-z0-9]+(?:\.[-a-z0-9]+)*\.(?:com|edu|info)/i
Как можно догадаться, это регулярное выражение определяет имена Интернет-сайтов (только для доменов .com, .edu, и .info). Отличием является использование дополнительного оператора ?:. Квалификатор части шаблона ?: отключает функцию извлечения данных, и тем самым дает круглым скобкам возможность обозначать последовательность действий. Например, в данном случае фраза (?:\.[-a-z0-9]+)* соответствует нулю или более элементам строки, например, ".ibm." Аналогично, фраза \.(?:com|edu|info) обозначает последовательность символов, за которой идет одна из строк com, edu, или info.
Отключение функции извлечения информации может показаться бессмысленным, если не подумать о том, что извлечение информации требует дополнительной обработки. Если программа обрабатывает большое количество данных, то отказ от извлечения может быть целесообразным. Кроме того, если вы имеете дело со сложным регулярным выражением, то отключение функции извлечения информации в некоторых частях шаблона может упростить извлечение тех частей шаблона, которые реально нужны.
Примечание: Модификатор i в конце регулярного выражения делает все сопоставления с шаблоном нечувствительными к регистру. Следовательно, подмножество a-z будет сопоставимо со всеми буквами, независимо от регистра.
В PHP есть и другие модификаторы частей шаблона (subpattern). Используя отладчик регулярных выражений, показанный в первой части данной серии (повторно показан в листинге 1), попробуйте сопоставить регулярное выражение ((?i)edu) со строками "EDU," "edu," и "Edu." Если в начале части шаблона задать модификатор (?i), то сопоставление с шаблоном не будет зависеть от регистра. Чувствительность к регистру восстанавливается, как только заканчивается данная часть шаблона. (Сравните с модификатором / ... /i, который применяется ко всему шаблону.)
Листинг 1. Простой отладчик регулярных выражений
Еще один полезный модификатор части шаблона - это (?x). Он позволяет добавлять в шаблон пробелы, что упрощает чтение регулярных выражений. Таким образом, часть шаблона ((?x) edu | com | info) (обратите внимание на пробелы между операторами дизъюнкции, которые добавлены для удобочитаемости) аналогична (edu|com|info). Для того, чтобы добавлять пробелы и комментарии в регулярное выражение, можно использовать глобальный модификатор / ... /x, см. листинг ниже.
Листинг 2. Добавление пробелов и комментариев
Как видно из листинга, при необходимости модификаторы можно объединять. Если необходимо включить в регулярное выражение символ пробела при использовании модификатора (?x), используйте метасимвол \s для поиска любого пробельного символа и \ (обратный слеш с пробелом) для поиска одного пробела, например, ((?x) hello \ there).
Оглядываемся вокруг
В подавляющем большинстве случаев регулярные выражения используются для проверки или декомпозиции входной информации на отдельные "лакомые кусочки", которые записываются в архив данных или сразу же обрабатываются приложением. Общепринятыми сферами применения являются: обработка полей форм, парсинг XML-кода и анализ протоколов.
Еще одна область применения регулярных выражений - форматирование, нормализация или улучшение читаемости данных. Вместо того чтобы использовать регулярные выражения для поиска и извлечения текста, при форматировании они применяются для поиска и вставки текста в надлежащее местоположение.
Вот пример полезного применения форматирования. Предположим, что Web-форма передает приложению значение зарплаты с округлением до целого доллара. Так как зарплата хранится в виде числа целого типа, то перед сохранением переданных данных приложение должно удалять из них знаки пунктуации. Однако при извлечении данных из хранилища, возможно, понадобится изменить их формат и сделать удобочитаемыми с помощью разделителей. В листинге 3 показано, как простой PHP-запрос преобразует сумму в долларах в число.
Листинг 3. Преобразование суммы в долларах в число
Вызов функции preg_replace() заменяет знак доллара, любой пробельный символ и все запятые -- на пустую строку, возвращая то, что предположительно является целым числом. Если проверка функцией is_numeric() подтверждает правильность входных данных, их можно сохранить.
А теперь давайте выполним обратную операцию - добавим к числу знак денежной единицы и запятые-разделители сотен, тысяч и миллионов. Для добавления запятых в определенных позициях можно написать программу для поиска этих компонентов, а можно воспользоваться операторами посмотри вперед и посмотри назад. Модификатор части шаблона ?<= обозначает посмотри назад (то есть влево) от текущей позиции. Модификатор ?= означает "посмотри вперед" (то есть вправо) от текущей позиции.
[pagebreak]
Итак, какие позиции нам нужны? Любое место в строке, при условии, что есть как минимум один символ слева и одна или более групп по три символа справа, не считая десятичной точки и количества центов. Соблюдая это правило и используя два модификатора, анализирующих символы справа и слева от определенной позиции и являющихся операторами нулевой ширины, мы можем достичь цели с помощью следующей инструкции:
Как работает это регулярное выражение? Начиная с первого символа строки и обрабатывая каждый символ, регулярное выражение отвечает на вопрос: "Есть ли хотя бы один символ слева и одна или несколько групп из трех символов справа?" Если да, то наш оператор нулевой ширины заменяется запятой.
Большинство сложных сопоставлений можно реализовать, используя стратегию, аналогичную приведенной выше. Например, вот еще один вариант использования оператора "посмотри вперед", который решает широко распространенную дилемму.
Листинг 4. Пример использования оператора "посмотри вперед" ("предвидение")
Оператор preg_replace() преобразует строку данных, разделенных запятыми, в строку данных, разделенных знаком табуляции. Предусмотрительным образом, он не заменяет запятые в строке, заключенной в кавычки.
Это регулярное выражение при каждом обнаружении запятой (на это указывает запятая в самом начале регулярного выражения) проверяет утверждение: "Впереди не было кавычек или было четное количество кавычек". Если утверждение верно, то запятую можно заменить знаком табуляции (the \t).
Если Вам не нравятся операторы «посмотри вперед» и «посмотри назад» или вы работаете с таким языком, в котором их нет, можно добавить запятые в число и с помощью обычного регулярного выражения. Однако для реализации такого решения потребуется много итераций.
Листинг 5. Добавление запятых
Давайте пройдем по коду. Сначала параметр зарплаты очищается от знаков пунктуации для моделирования ситуации чтения целого числа из базы данных. Затем выполняется цикл в поисках позиций, где за одним числовым символом ((\d) идут три числовых символа ((\d\d\d\): если обнаруживается граница слова, заданная как \b, цикл прекращается. Граница слова -- это еще один оператор нулевой ширины, который соответствует следующим позициям:
* Перед первым символом строки, если это буква слова.
* За последним символом строки, если это буква слова.
* Между буквой слова и небуквенным символом, непосредственно за буквой слова.
* Между небуквенным символом и буквой слова, непосредственно за небуквенным символом.
Таким образом, примерами правильных границ слова являются пробел, точка и запятая.
Благодаря внешнему циклу регулярное выражение перемещается слева направо в поисках цифры, за которой идут три цифры и граница слова. При обнаружении совпадения между двумя частями шаблона добавляется запятая. Цикл должен продолжаться до тех пор, пока оператор preg_replace() находит совпадения, что задано в условии $old != $pretty_print.
Жадность и лень
Регулярные выражения обладают большими возможностями, иногда даже слишком большими. Например, давайте рассмотрим, что произойдет, если регулярное выражение ".*" будет обрабатывать строку "The author of 'Wicked' also wrote 'Mirror, Mirror.'" Вероятно, вы предполагаете, что preg_match() вернет два совпадения, и с удивлением обнаружите, что результат всего один: 'Wicked' also wrote 'Mirror, Mirror.'
Почему? Если не задать иное, то такие операторы как * (ноль или более) и + (один или более) -- "жадные". Если сопоставление с образцом может продолжаться, то они и будут его продолжать до тех пор, пока не будет возвращен максимальный результат из возможных. Для сохранения минимальных совпадений необходимо принудительно заставлять определенные операторы быть "ленивыми". "Ленивые" операторы находят самое короткое совпадение и на этом останавливаются. Чтобы сделать оператор более "ленивым", добавьте суффикс в виде знака вопроса. Пример показан в листинге 6.
Листинг 6. Добавление суффикса в виде знака вопроса
Регулярное выражение ".*?" расшифровывается следующим образом: "найти кавычку, за которой идет ровно столько символов с последующей кавычкой.
Однако иногда оператор * может быть слишком "ленивым". Например, посмотрите на следующий фрагмент кода. Что он делает?
Листинг 7. Простой отладчик регулярных выражений
Что вы загадали? "123"? "1"? Нет результата? На самом деле результатом будет Array ( [0] => [1] => ), означающий, что совпадение было найдено, но никаких данных извлечено не было. Почему? Вспомните, что оператор * ищет совпадения с нулем или более символов. В данном случае, выражение [0-9]* находит совпадение с нулем символов от начала строки, и обработка заканчиваетс.
Для решения данной проблемы добавьте оператор нулевой ширины для привязки совпадения, который заставляет регулярное выражение продолжать сопоставления; /([0-9]*\b/.
Советы и рекомендации
С помощью регулярных выражений можно решать как простые, так и сложные задачи при обработке текста. Начните с небольшой группы операторов и по мере того, как вы будете набираться опыта, расширяйте свой словарь. В качестве вознаграждения за ваши старания -- некоторые советы и рекомендации.
Создание переносимых регулярных выражений с помощью классов символов
Вам уже знакомы метасимволы, например, \s - соответствует любому пробельному символу. Кроме того, большинство реализаций регулярных выражений поддерживает предопределенные классы символов, которые более просты в использовании и переносимы с одного письменного языка на другой. Например, класс символов [:punct:] замещает все символы пунктуации в данном языке. Вместо [0-9] можно использовать [:digit:] и более переносимое замещение [:alpha:] вместо [-a-zA-Z0-9_]. Например, можно убрать все знаки пунктуации, используя:
Класс символов представляет собой более сжатую форму по сравнению с подробным описанием всех символов пунктуации. Полный перечень классов символов можно найти в документации по версии языка PHP.
Как исключить то, что вы не ищете
Как показано в примере с данными, разделенными символом табуляции, в качестве значений, разделенных запятыми (CSV), иногда проще и точнее задать список тех вариантов, которые не нужно находить (сопоставлять). Последовательность, начинающаяся со знака "крышка" (^) будет соответствовать любому символу, не принадлежащему данной последовательности. Например, для проверки правильности телефонных номеров для США можно использовать регулярное выражение /[2-9][0-9]{2}[2-9][0-9]{2}[0-9]{4}/. Используя набор ограничений можно написать регулярное выражение в более явном виде /[^01][0-9]{2}[^01][0-9]{2}[0-9]{4}/. Оба регулярных выражения работают, хотя смысл последнего, вероятно, более понятен.
Пропуск новой строки
Если во входных данных несколько строк, стандартного регулярного выражения будет недостаточно, так как сканирование прекращается на начале новой строки, которая обозначается $. Однако, если воспользоваться модификаторами s или m, то регулярное выражение будет обрабатывать входные данные по-другому. Первый модификатор рассматривает строковую последовательность как одну строку, где точка указывает на начало новой строки (обычно она этого не делает). Второй рассматривает строковую последовательность как несколько строк, где ^ и $ соответствуют началу и концу любой строки, соответственно. Приведем пример. Если задать $string = "Hello,\nthere";, то оператор preg_match( "/.*/s", $string, $matches) параметру $matches[0] присвоит значение Hello,\nthere. (При удалении s будет выдано Hello.)
Компоненты Delphi для работы с базами данных были созданы в расчете на работу с SQL и архитектурой клиент/сервер. При работе с ними вы можете воспользоваться характеристиками расширенной поддержки удаленных серверов. Delphi осуществляет эту поддержку двумя способами.
1. Введение
Во-первых, непосредственные команды из Delphi позволяют разработчику управлять таблицами, устанавливать пределы, удалять, вставлять и редактировать существующие записи.
Второй способ заключается в использовании запросов на языке SQL, где строка запроса передается на сервер для ее разбора, оптимизации, выполнения и передачи обратно результатов.
Данный документ делает акцент на втором методе доступа к базам данных, на основе запросов SQL (pass-through). Авторы не стремились создать курсы по изучению синтаксиса языка SQL и его применения, они ставили перед собой цель дать несколько примеров использования компонентов TQuery и TStoredProc. Но чтобы сделать это, необходимо понимать концепцию SQL и знать как работают selects, inserts, updates, views, joins и хранимые процедуры (stored procedures). Документ также вскользь касается вопросов управления транзакциями и соединения с базой данных, но не акцентирует на этом внимание. Итак, приступая к теме, создайте простой запрос типа SELECT и отобразите результаты.
2. Компонент TQuery
Если в ваших приложениях вы собираетесь использовать SQL, то вам непременно придется познакомиться с компонентом TQuery. Компоненты TQuery и TTable наследуются от TDataset. TDataset обеспечивает необходимую функциональность для получения доступа к базам данных. Как таковые, компоненты TQuery и TTable имеют много общих признаков. Для подготовки данных для показа в визуальных компонентах используется все тот же TDatasource. Также, для определения к какому серверу и базе данных необходимо получить доступ, необходимо задать имя псевдонима. Это должно выполняться установкой свойства aliasName объекта TQuery.
Свойство SQL
Все же TQuery имеет некоторую уникальную функциональность. Например, у TQuery имеется свойство с именем SQL. Свойство SQL используется для хранения SQL-запроса. Ниже приведены основные шаги для составления запроса, где все служащие имеют зарплату свыше $50,000.
Создайте объект TQuery
Задайте псевдоним свойству DatabaseName. (Данный пример использует псевдоним IBLOCAL, связанный с демонстрационной базой данных employee.gdb).
Выберите свойство SQL и щелкните на кнопке с текстом - '...' (три точки, Инспектор Объектов - В.О.). Должен появиться диалог редактора списка строк (String List Editor).
Введите:
. Нажмите OK.
Выберите в Инспекторе Объектов свойство Active и установите его в TRUE.
Разместите на форме объект TDatasource.
Установите свойство Dataset у TDatasource в Query1.
Разместите на форме TDBGrid.
Установите его свойство Datasource в Datasource1.
Свойство SQL имеет тип TStrings. Объект TStrings представляет собой список строк, и чем-то похож на массив. Тип данных TStrings имеет в своем арсенале команды добавления строк, их загрузки из текстового файла и обмена данными с другим объектом TStrings. Другой компонент, использующий TStrings - TMemo. В демонстрационном проекте ENTRSQL.DPR (по идее, он должен находится на отдельной дискетте, но к "Советам по Delphi" она не прилагается - В.О.), пользователь должен ввести SQL-запрос и нажать кнопку "Do It" ("сделать это"). Результаты запроса отображаются в табличной сетке. В Листинге 1 полностью приведен код обработчика кнопки "Do It".
Листинг 1
Свойство Params
Этого должно быть достаточно для пользователя, знающего SQL. Тем не менее, большинство пользователей не знает этого языка. Итак, ваша работа как разработчика заключается в предоставлении интерфейса и создании SQL-запроса. В Delphi, для создания SQL-запроса на лету можно использовать динамические запросы. Динамические запросы допускают использование параметров. Для определения параметра в запросе используется двоеточие (:), за которым следует имя параметра. Ниже приведе пример SQL-запроса с использованием динамического параметра:
Если вам нужно протестировать, или установить для параметра значение по умолчанию, выберите свойство Params объекта Query1. Щелкните на кнопке '...'. Должен появиться диалог настройки параметров. Выберите параметр Dept_no. Затем в выпадающем списке типов данных выберите Integer. Для того, чтобы задать значение по умолчанию, введите нужное значение в поле редактирования "Value".
Для изменения SQL-запроса во время выполнения приложения, параметры необходимо связать (bind). Параметры могут изменяться, запрос выполняться повторно, а данные обновляться. Для непосредственного редактирования значения параметра используется свойство Params или метод ParamByName. Свойство Params представляет из себя массив TParams. Поэтому для получения доступа к параметру, необходимо указать его индекс. Для примера,
Query1.params[0].asInteger := 900;
Свойство asInteger читает данные как тип Integer (название говорит само за себя). Это не обязательно должно указывать но то, что поле имеет тип Integer. Например, если тип поля VARCHAR(10), Delphi осуществит преобразование данных. Так, приведенный выше пример мог бы быть записан таким образом:
Query1.params[0].asString := '900';
или так:
Query1.params[0].asString := edit1.text;
Если вместо номера индекса вы хотели бы использовать имя параметра, то воспользуйтесь методом ParamByName. Данный метод возвращает объект TParam с заданным именем. Например:
Query1.ParamByName('DEPT_NO').asInteger := 900;
В листинге 2 приведен полный код примера.
Листинг 2
Обратите внимание на процедуру, первым делом подготовливающую запрос. При вызове метода prepare, Delphi посылает SQL запрос на удаленный сервер. Сервер выполняет грамматический разбор и оптимизацию запроса. Преимущество такой подготовки запроса состоит в его предварительном разборе и оптимизации. Альтернативой здесь может служить подготовка сервером запроса при каждом его выполнении. Как только запрос подготовлен, подставляются необходимые новые параметры, и запрос выполняется.
[pagebreak]
Источник данных
В предыдущем примере пользователь мог ввести номер отдела, и после выполнения запроса отображался список сотрудников этого отдела. А как насчет использования таблицы DEPARTMENT, позволяющей пользователю легко перемещаться между пользователями и отделами?
Примечание: Следующий пример использует TTable с именем Table1. Для Table1 имя базы данных IBLOCAL, имя таблицы - DEPARTMENT. DataSource2 TDatasource связан с Table1. Таблица также активна и отображает записи в TDBGrid.
Способ подключения TQuery к TTable - через TDatasource. Есть два основных способа сделать это. Во-первых, разместить код в обработчике события TDatasource OnDataChange. Например, листинг 3 демонстрирует эту технику.
Листинг 3 - Использования события OnDataChange для просмотра дочерних записей
Техника с использованием OnDataChange очень гибка, но есть еще легче способ подключения Query к таблице. Компонент TQuery имеет свойство Datasource. Определяя TDatasource для свойства Datasource, объект TQuery сравнивает имена параметров в SQL-запросе с именами полей в TDatasource. В случае общих имен, такие параметры заполняются автоматически. Это позволяет разработчику избежать написание кода, приведенного в листинге 3 (*** приведен выше ***).
Фактически, техника использования Datasource не требует никакого дополнительного кодирования. Для поключения запроса к таблице DEPT_NO выполните действия, приведенные в листинге 4.
Листинг 4 - Связывание TQuery c TTable через свойство Datasource
Выберите у Query1 свойство SQL и введите:
Выберите свойство Datasource и назначьте источник данных, связанный с Table1 (Datasource2 в нашем примере)
Выберите свойство Active и установите его в True
Это все, если вы хотите создать такой тип отношений. Тем не менее, существуют некоторые ограничения на параметризованные запросы. Параметры ограничены значениями. К примеру, вы не можете использовать параметр с именем Column или Table. Для создания запроса, динамически изменяемого имя таблицы, вы могли бы использовать технику конкатенации строки. Другая техника заключается в использовании команды Format.
Команда Format
Команда Format заменяет параметры форматирования (%s, %d, %n и пр.) передаваемыми значениями. Например,
Format('Select * from %s', ['EMPLOYEE'])
Результатом вышеприведенной команды будет 'Select * from EMPLOYEE'. Функция буквально делает замену параметров форматирования значениями массива. При использовании нескольких параметров форматирования, замена происходит слева направо. Например,
Результатом команды форматирования будет 'Select * from EMPLOYEE where EMP_ID=3'. Такая функциональность обеспечивает чрезвычайную гибкость при динамическом выполнении запроса. Пример, приведенный ниже в листинге 5, позволяет вывести в результатах поле salary. Для поля salary пользователь может задавать критерии.
Листинг 5 - Использование команды Format для создания SQL-запроса
В этом примере мы используем методы Clear и Add свойства SQL. Поскольку "подготовленный" запрос использует ресурсы сервера, и нет никакой гарантии что новый запрос будет использовать те же таблицы и столбцы, Delphi, при каждом изменении свойства SQL, осуществляет операцию, обратную "подготовке" (unprepare). Если TQuery не был подготовлен (т.е. свойство Prepared установлено в False), Delphi автоматически подготавливает его при каждом выполнении. Поэтому в нашем случае, даже если бы был вызван метод Prepare, приложению от этого не будет никакой пользы.
Open против ExecSQL
В предыдущих примерах TQuerie выполняли Select-запросы. Delphi рассматривает результаты Select-запроса как набор данных, типа таблицы. Это просто один класс допустимых SQL-запросов. К примеру, команда Update обновляет содержимое записи, но не возвращает записи или какого-либо значения. Если вы хотите использовать запрос, не возвращающий набор данных, используйте ExecSQL вместо Open. ExecSQL передает запрос для выполнения на сервер. В общем случае, если вы ожидаете, что получите от запроса данные, то используйте Open. В противном случае допускается использование ExecSQL, хотя его использование с Select не будет конструктивным. Листинг 6 содержит код, поясняющий сказанное на примере.
Листинг 6
Все приведенные выше примеры предполагают использования в ваших приложениях запросов. Они могут дать солидное основание для того, чтобы начать использовать в ваших приложениях TQuery. Но все же нельзя прогнозировать конец использования SQL в ваших приложених. Типичные серверы могут предложить вам другие характеристики, типа хранимых процедур и транзакций. В следующих двух секциях приведен краткий обзор этих средств.
[pagebreak]
3. Компонент TStoredProc
Хранимая процедура представляет собой список команд (SQL или определенного сервера), хранимых и выполняемых на стороне сервера. Хранимые процедуры не имеют концептуальных различий с другими типами процедур. TStoredProc наследуется от TDataset, поэтому он имеет много общих характеристик с TTable и TQuery. Особенно заметно сходство с TQuery. Поскольку хранимые процедуры не требуют возврата значений, те же правила действуют и для методов ExecProc и Open. Каждый сервер реализует работу хранимых процедур с небольшими различиями. Например, если в качестве сервера вы используете Interbase, хранимые процедуры выполняются в виде Select-запросов. Например, чтобы посмотреть на результаты хранимой процедуры, ORG_CHART, в демонстрационной базе данных EMPLOYEE, используйте следующих SQL-запрос:
При работе с другими серверами, например, Sybase, вы можете использовать компонент TStoredProc. Данный компонент имеет свойства для имен базы данных и хранимой процедуры. Если процедура требует на входе каких-то параметров, используйте для их ввода свойство Params.
4. TDatabase
Компонент TDatabase обеспечивает функциональность, которой не хватает TQuery и TStoredProc. В частности, TDatabase позволяет создавать локальные псевдонимы BDE, так что приложению не потребуются псевдонимы, содержащиеся в конфигурационном файле BDE. Этим локальным псевдонимом в приложении могут воспользоваться все имеющиеся TTable, TQuery и TStoredProc. TDatabase также позволяет разработчику настраивать процесс подключения, подавляя диалог ввода имени и пароля пользователя, или заполняя необходимые параметры. И, наконец, самое главное, TDatabase может обеспечивать единственную связь с базой данных, суммируя все операции с базой данных через один компонент. Это позволяет элементам управления для работы с БД иметь возможность управления транзакциями.
Транзакцией можно считать передачу пакета информации. Классическим примером транзакции является передача денег на счет банка. Транзакция должна состоять из операции внесения суммы на новый счет и удаления той же суммы с текущего счета. Если один из этих шагов по какой-то причине был невыполнен, транзакция также считается невыполненной. В случае такой ошибки, SQL сервер позволяет выполнить команду отката (rollback), без внесения изменений в базу данных. Управление транзакциями зависит от компонента TDatabase. Поскольку транзакция обычно состоит из нескольких запросов, вы должны отметить начало транзакции и ее конец. Для выделения начала транзакции используйте TDatabase.BeginTransaction. Как только транзакция начнет выполняться, все выполняемые команды до вызова TDatabase.Commit или TDatabase.Rollback переводятся во временный режим. При вызове Commit все измененные данные передаются на сервер. При вызове Rollback все изменения теряют силу. Ниже в листинге 7 приведен пример, где используется таблица с именем ACCOUNTS. Показанная процедура пытается передать сумму с одного счета на другой.
Листинг 7
И последнее, что нужно учесть при соединении с базой данных. В приведенном выше примере, TDatabase использовался в качестве единственного канала для связи с базой данных, поэтому было возможным выполнение только одной транзакции. Чтобы выполнить это, было определено имя псевдонима (Aliasname). Псевдоним хранит в себе информацию, касающуюся соединения, такую, как Driver Type (тип драйвера), Server Name (имя сервера), User Name (имя пользователя) и другую. Данная информация используется для создания строки соединения (connect string). Для создания псевдонима вы можете использовать утилиту конфигурирования BDE, или, как показано в примере ниже, заполнять параметры во время выполнения приложения.
TDatabase имеет свойство Params, в котором хранится информация соединения. Каждая строка Params является отдельным параметром. В приведенном ниже примере пользователь устанавливает параметр User Name в поле редактирования Edit1, а параметр Password в поле Edit2. В коде листинга 8 показан процесс подключения к базе данных:
Листинг 8
Этот пример показывает как можно осуществить подключение к серверу без создания псевдонима. Ключевыми моментами здесь являются определение DriverName и заполнение Params информацией, необходимой для подключения. Вам не нужно определять все параметры, вам необходимо задать только те, которые не устанавливаются в конфигурации BDE определенным вами драйвером базы данных. Введенные в свойстве Params данные перекрывают все установки конфигурации BDE. Записывая параметры, Delphi заполняет оставшиеся параметры значениями из BDE Config для данного драйвера. Приведенный выше пример также вводит такие понятия, как сессия и метод GetTableNames. Это выходит за рамки обсуждаемой темы, достаточно упомянуть лишь тот факт, что переменная session является дескриптором database engine. В примере она добавлена только для "показухи".
Другой темой является использование SQLPASSTHRU MODE. Этот параметр базы данных отвечает за то, как натив-команды базы данных, такие, как TTable.Append или TTable.Insert будут взаимодействовать с TQuery, подключенной к той же базе данных. Существуют три возможных значения: NOT SHARED, SHARED NOAUTOCOMMIT и SHARED AUTOCOMMIT. NOT SHARED означает, что натив-команды используют одно соединение с сервером, тогда как запросы - другое. Со стороны сервера это видится как работа двух разных пользователей. В любой момент времени, пока транзакция активна, натив-команды не будут исполняться (committed) до тех пор, пока транзакция не будет завершена. Если был выполнен TQuery, то любые изменения, переданные в базу данных, проходят отдельно от транзакции.
Два других режима, SHARED NOAUTOCOMMIT и SHARED AUTOCOMMIT, делают для натив-команд и запросов общим одно соединение с сервером. Различие между двумя режимами заключаются в передаче выполненной натив-команды на сервер. При выбранном режиме SHARED AUTOCOMMIT бессмысленно создавать транзакцию, использующую натив-команды для удаления записи и последующей попыткой осуществить откат (Rollback). Запись должна быть удалена, а изменения должны быть сделаны (committed) до вызова команды Rollback. Если вам нужно передать натив-команды в пределах транзакции, или включить эти команды в саму транзакцию, убедитесь в том, что SQLPASSTHRU MODE установлен в SHARED NOAUTOCOMMIT или в NOT SHARED.
5. Выводы
Delphi поддерживает множество характеристик при использовании языка SQL с вашими серверами баз данных. На этой ноте разрешите попрощаться и пожелать почаще использовать SQL в ваших приложениях.