MySQL+Lazarus: Работа и базой данной на Web сервере из Lazarus |
16.04.2009 aRix |
Продолжая осваивать работу с базами данных в Lazarus, я решил посмотреть, как реализовать работу с удаленным MySQL сервером. У меня есть небольшой сайт на самописном PHP движке, который берет информацию из MySQL базы данных. Таблица со статьями называется myArtTable и имеет простую структуру (Id, text, description и keywords). Мне всегда хотелось иметь инструмент, с помощью которого можно было бы в обход браузера работать с контентом сайта. Собственно написанием такой штуковины я и предлагаю заняться, а попутно объяснить Вам механизмы работы с базой данных в Lazarus.
Создайте пустой проект. В папку проекта необходимо скопировать библиотеку DLL для работы с MySQL. Скачать ее можно здесь: libmysql.dll.
На моем Web сервере установлен MySQL 5.03, поэтому, следуя рекомендациям, приведенным в статье "Использование SQLdb в Lazarus: основы работы с базами данных", я помещаю на форму компоненты TMySQL50Connection, TSQLTransaction, TSQLQuery из панели SQLbd; и компонент TDatasource из панели Data Access.
Настроим связи между этими компонентами.
Для подключения к базе данных необходимо для объекта MySQL50Connection1 указать адрес сервера (свойство HostName), название базы данных (свойство DatabaseName), имя пользователя (свойство UserName) и пароль для доступа к базе данных (свойство Password). Если Вы подключаетесь к базе данных на своем web сервере, значения этих свойств можно узнать у Вашего хостера. В моем случае я просто зашел в панель управления сайтом и скопировал все необходимые мне поля из соответствующего раздела.
Объекты класса TSQLQuery представляют собой наборы данных. В него загружается копия таблицы с сервера БД, с которой потом и осуществляется вся работа.
TSQLQuery поддерживает два принципиально разных способа доступа к данными: навигационный, который заключается в обработке каждой отдельной(текущей) записи(строки) таблицы; и реляционный, основанный на обработке сразу группы записей, посредствам SQL-запросов.
Сначала познакомимся с реляционным способом доступа к данным, в частности рассмотрим способы выполнения SQL запросов. SQL запросы можно разделить на две группы: возвращающие и не возвращающие результат. Например, запрос
Select * from myArtTable;подразумевает запись в набор данных копии таблицы myArtTable. Для его выполнения нужно использовать код:
SQLQuery1.Close; SQLQuery1.SQL.Clear; SQLQuery1.SQL.Add(Select * from myArtTable;'); SQLQuery1.Open;
Мы сначала закрываем набор данных SQLQuery1, вызывая его метод Close (Аналогичного результата можно добиться установив свойство Active в false). Если набор закрыт, его связь с базой данных разорвана. Затем мы очищаем свойство SQL с помощью метода Clear. С помощью метода Add записываем в него текст нового запроса. Исполняется запрос при выполнении команды Open, которая переводит набор данных SQLQuery1 в открытый режим и записывает в него результаты выполнения SQL запроса.
Если SQL запрос не подразумевает возврата таблиц данных (запросы INSERT и UPDATE), необходимо воспользоваться альтернативным способом его выполнения:
SQLQuery1.Close; SQLQuery1.SQL.Clear; SQLQuery1.SQL.Add('INSERT INTO myArtTable (text, description , keywords) VALUES('+#39+memo3.text+#39+', '+#39+memo2.text+#39+', '+#39+memo1.text+#39+');'); SQLQuery1.ExecSQL;
При этом, при попытке перевести набор данных в открытый режим (выполнить SQLQuery1.Open;) возникнет ошибка. Для ее устранения нужно либо записать в свойство SQL новый запрос, возвращающий таблицу, так показано ниже:
SQLQuery1.Close; SQLQuery1.SQL.Clear; SQLQuery1.SQL.Add('INSERT INTO myArtTable (text, description , keywords) VALUES('+#39+memo3.text+#39+', '+#39+memo2.text+#39+', '+#39+memo1.text+#39+');'); SQLQuery1.ExecSQL; SQLQuery1.SQL.Text:='SELECT * from myArtTable;'; SQLQuery1.Open;
Либо создать и использовать для таких SQL запросов отдельный набор данных (SQLQuery2), который никогда не переводить в открытый режим.
Будем подключаться к удаленной базе данных не сразу, а после получения явной команды от пользователя (щелчка по соответствующей кнопке), поэтому установим в инспекторе объектов свойство Сonnected компонента TMySQL50Connection и свойства Active компонент TSQLTransaction и TSQLQuery в false.
Создадим на форме кнопку «Подключиться». В обработчике нажатия напишем:
procedure TForm1.Button1Click(Sender: TObject); begin isAllOk:=true; try MySQL50Connection1.Connected:=true; except ShowMessage(' Не могу подключиться к базе данных'); exit; end; try SQLTransaction1.Active:=true; except ShowMessage(' Не могу создать транзакцию'); exit; end; try SQLQuery1.Active:=false; SQLQuery1.SQL.Clear; SQLQuery1.sql.add('SET character_set_client='+#39+'utf8'+#39+', character_set_connection='+#39+'cp1251'+#39+',character_set_results='+#39+'utf8'+#39+';'); SQLQuery1.ExecSQL; SQLQuery1.SQL.Clear; SQLQuery1.sql.add('SELECT * from myArtTable;'); SQLQuery1.Open; except ShowMessage(' Ошибка при выполнении SQL запроса.'); exit; end; end;
Таким образом, сначала производится попытка подключения к MySQL базе, если она прошла успешно, создается новая транзакция, после чего при активации объекта SQLQuery1 выполняется SQL запрос к базе данных, выбирающей все строки из таблицы. Перед тем, как получить таблицу с сервера, необходимо соответствующим образом настроить кодировки. В моей базе данные хранятся в кодировке cp1251, поэтому я выполняю запрос
SET character_set_client="utf8", character_set_connection="cp1251", character_set_results="utf8"
При отключении от базы данных действуем в обратном порядке. Зададим код отключения в обработчике события OnDestroy формы
procedure TForm1.FormDestroy(Sender: TObject); begin SQLQuery1.Active:=false; SQLTransaction1.Commit; MySQL50Connection1.Connected:=false; end;
Навигационный способ подразумевает последовательную работу с записями(строками) таблицы, содержащейся в наборе данных. На навигационном способе доступа основана работа визуальных компонент из вкладки «Data Controls». Разместим на нашей форме компоненты TDBGrid, TDBNavigator и три компонента TDBMemo. И установим в их свойствах DataSource ссылку на DataSource1. В свойства DataField объектов DBMemo1, DBMemo2, DBMemo3 запишем description, text и keywords соответственно. (Напоминаю, что description, text и keywords – это название полей(колонок) в таблице myArtTable.) Поскольку наш набор данных первоначально находится в закрытом состоянии (Action=false), Lazarus будет выдавать предупреждение при попытке ввода названий полей. Не обращайте внимания - это нормально.
Запустите программу и нажмите кнопу «Подключиться…». После подключения к базе данных полученная с сервера таблица будет отображаться в объекте DBGrid1. Стрелочкой слева обозначена текущая запись. С помощью кнопок панели DBNavigator1 можно перемещаться по строкам таблицы. Вы также можете редактировать записи, однако после закрытия программы все сделанные изменения сбросятся. Для их сохранения в базу необходимо вызвать метод ApplyUpdates:
SQLQuery1.ApplyUpdates;
Приведу методы класса TSQLQuery, предназначенные для навигации по базе:
Для того чтобы получить значения какого-нибудь поля записи, можно воспользоваться методом FieldByName(fn:string), где fn – название поля (колонки) таблицы. Этот же метод можно использовать для записи новых данных в таблицу. Формат чтения/записи указывается с помощью свойств AsString, AsInteger, AsFloat, AsDataTime, … Например, чтобы записать текущее значения поля id в Label, можно воспользоваться кодом:
Label1.caption:=SQLQuery1.FieldByName(‘id’).AsString;
Приведем также пример редактирования текущей строки таблицы
SQLQuery1.Edit; SQLQuery1.FieldByName(‘keywords’).AsString:=’Lazarus жжот’; SQLQuery1.FieldByName(‘text’).AsString:=’Новый текст’; SQLQuery1.Post; SQLQuery1.ApplyUpdates;
Стоит отметить, что не каждый набор данных можно редактировать навигационным способом. Чтобы получить в результате SQL запроса редактируемый набор (то есть такой, что внесенные изменения можно было сохранить в базу данных), необходимо выполнение следующих условий:
Вообще механизм транзакции необходим для сохранения целостности базы данных. Допустим, для внесения актуальных данных в базу Вам необходимо записать в разные таблицы большое количество информации. Если в процессе записи выключится электричество, то часть таблиц будут содержать актуальную информацию, а часть старую. В результате база данных окажется испорченной. Избежать этого позволяет механизм транзакций. Если все операции записи завершились успешно, транзакция считается успешной и все изменения в таблицах базы считаются подтвержденными. Если же хотя бы одна операция записи не выполнена, транзакция считается неудачной и таблицы базы данных возвращаются к состоянию, которое они имели до начала транзакции.
Для работы с транзакциями в Lazarus добавлен компонент TSQLTransaction. Однако, в настоящее время он не работает с MySQL базами данных. TSQLTransaction автоматически переходит в активное состояние при открытии набора данных (TSQLQuery) и закрывается при его закрытии. Для явного подтверждения успешности транзакции можно использовать метод TSQLTransaction.Commit. Вызывать его следует сразу после TSQLQuerty.ApplyUpdates; Для отката транзакции можно использовать метод TSQLTransaction.Rollback.
Итак, в этой статье я постарался собрать воедино свой небольшой опыт по работе с базой MySQL из Lazarus. Механизм работы с другими базами данных в целом не отличается от описанного здесь.
SQL запрос для создания таблицы myArtTable
CREATE TABLE `myArtTable` ( `id` int(11) NOT NULL auto_increment, `text` text NOT NULL, `description` text NOT NULL, `keywords` text NOT NULL, PRIMARY KEY (`id`) ) ENGINE=MyISAM AUTO_INCREMENT=16 DEFAULT CHARSET=cp1251 AUTO_INCREMENT=16;