Публикации Lazarus

MySQL+Lazarus: Работа и базой данной на Web сервере из Lazarus

16.04.2009
aRix

Продолжая осваивать работу с базами данных в Lazarus, я решил посмотреть, как реализовать работу с удаленным MySQL сервером. У меня есть небольшой сайт на самописном PHP движке, который берет информацию из MySQL базы данных. Таблица со статьями называется myArtTable и имеет простую структуру (Id, text, description и keywords). Мне всегда хотелось иметь инструмент, с помощью которого можно было бы в обход браузера работать с контентом сайта. Собственно написанием такой штуковины я и предлагаю заняться, а попутно объяснить Вам механизмы работы с базой данных в Lazarus.

TMySQL50Connection, TSQLTransaction, TSQLQuery – компоненты для работы с базой данных

Создайте пустой проект. В папку проекта необходимо скопировать библиотеку DLL для работы с MySQL. Скачать ее можно здесь: libmysql.dll.

На моем Web сервере установлен MySQL 5.03, поэтому, следуя рекомендациям, приведенным в статье "Использование SQLdb в Lazarus: основы работы с базами данных", я помещаю на форму компоненты TMySQL50Connection, TSQLTransaction, TSQLQuery из панели SQLbd; и компонент TDatasource из панели Data Access.

Настроим связи между этими компонентами.

  • В свойстве Transaction объекта MySQL50Connection1 выберите SQLTransaction1 (я не менял присваиваемые по умолчанию имена объектов).
  • В свойстве Database объекта SQLQuery1 выберите MySQL50Connection1
  • В свойстве Transaction объекта SQLQuery1 выберите SQLTransaction1
  • В свойстве DataSet объекта Datasource1 выберите SQLQuery1

Для подключения к базе данных необходимо для объекта 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), который никогда не переводить в открытый режим.

Подключение и отключение от базы данных в Lazarus

Будем подключаться к удаленной базе данных не сразу, а после получения явной команды от пользователя (щелчка по соответствующей кнопке), поэтому установим в инспекторе объектов свойство С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, предназначенные для навигации по базе:

  • TSQLQuery.Next – перейти на запись вперед
  • TSQLQuery.Prior – перейти на запись назад
  • TSQLQuery.First – перейти на первую запись
  • TSQLQuery.Last – перейти на последнюю запись
  • TSQLQuery.Insert – добавить новую запись
  • TSQLQuery.Delete – удалить запись
  • TSQLQuery.Edit – перевести набор данных в режим редактирования
  • TSQLQuery.Post – сохранить сделанные изменения в набор данных
  • TSQLQuery.Refresh – обновить таблицу

Для того чтобы получить значения какого-нибудь поля записи, можно воспользоваться методом 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 запроса редактируемый набор (то есть такой, что внесенные изменения можно было сохранить в базу данных), необходимо выполнение следующих условий:

  • данные отбираются только из одной таблицы;
  • таблица допускает модификацию;
  • в запросе не используется DISTINCT и статические функции;
  • в запросе не применяются соединения таблиц;
  • в запросе отсутствуют подзапросы и вложенные запросы;
  • не используется группирование данных;
  • сортировка применяется только к индексным полям;

Использование транзакций и TSQLTransaction в Lazarus

Вообще механизм транзакции необходим для сохранения целостности базы данных. Допустим, для внесения актуальных данных в базу Вам необходимо записать в разные таблицы большое количество информации. Если в процессе записи выключится электричество, то часть таблиц будут содержать актуальную информацию, а часть старую. В результате база данных окажется испорченной. Избежать этого позволяет механизм транзакций. Если все операции записи завершились успешно, транзакция считается успешной и все изменения в таблицах базы считаются подтвержденными. Если же хотя бы одна операция записи не выполнена, транзакция считается неудачной и таблицы базы данных возвращаются к состоянию, которое они имели до начала транзакции.

Для работы с транзакциями в 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;


Исходный код проекта.
Источник: homepg.ru

Актуальные версии
FPC3.2.2release
Lazarus3.2release
MSE5.10.0release
fpGUI1.4.1release
links