Delphi, FMX, FireDAC, MySQL и Access violation at adress…

Access violation at adress

Сообщение операционной системы Access violation at adress... является не редким. Одна из причин его появления может быть не верное подключение разрабатываемого Delphi приложения к базе данных.

В одной из предыдущих своих статей я описывал способ подключения приложения Delphi, разрабатываемое с помощью фреймворка FMX к базе данных с использованием механизма доступа к данным FireDAC на примере СУБД MySQL. Вот эта самая статья.

При подключении к базе данных я привык располагать объект Connection на основной форме приложения. А так как я люблю писать приложения в стиле MDI, то соответственно, я размещаю данный компонент в MDI-форме приложения. О видах интерфейсов пользователей рассказано в статье «Как создать MDI-приложение в FireMonkey».

Хотя конечно современные подходы к программированию подразумевают, что не визуальные компоненты доступа к данным следует размещать в специальном модуле данных (DataModules). Но все-же в моих приложениях мне удобно размещать их по старинке на формах, тем более, особенно, когда речь не идет о каком-либо масштабировании приложения в будущем.

Ну так вот, разместив объект FDConnection на главной форме приложения, я обнаружил следующую проблему. Когда я создаю какую-либо форму и на этой форме размещаю набор данных (FDQuery), то я не могу его подключить к объекту FDConnection, который расположен на главной форме приложения. При открытии такого набора данных система сразу выдает ошибку по типу: «Access violation at adress...», которая собственно говорит о том, что происходит нарушение доступа по адресу (который обычно указывает на память).

Access violation at adress
Access violation at adress

Причем хочу заметить, что, если я использую механизм доступа к данным ADO (в FMX-приложении его можно использовать без ограничений при условии, что приложение будет компилироваться только под Windows. Спросите, зачем компилировать только под Windows И писать при этом на FMX вместо VCL? Ну может быть, если хочется более красивых визуальных эффектов, например), то доступ осуществляется без ошибок, все работает отлично и точно также, как и при использовании ADO в приложении VCL.

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

Мне удалось найти решение того, как избежать этой проблемы. Чтобы решить эту ситуацию потребуется разместить FDConnection не на главной форме приложения, а в модуле доступа к данным. То есть, потребуется тот самый, более профессиональный подход, о котором я написал в начале статьи, который заключается в том, что все не визуальные компоненты размещаются в модуле доступа к данным (DataModules).

Но я ограничился экспериментом и разместил в DataModules только fdConnection (напомню, что речь идет сейчас о приложении FMX).

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

Более того, модулей доступа к данным в приложении может быть несколько. Теперь дав То есть, самым обычным образом, подобно тому, как создается новая форма в приложении, я создал модуль DataModule1 и поместил в него компонент fdConnection, который связал с базой данных.

Итак, выше я написал, что разместил в модуле доступа к данным компонент fdConnection и подключил его к базе данных MySQL. Для этого я использовал событие DataModuleCreate модуля DataModule1. Ну то есть, раньше я этот код использовал в onCreate главной формы приложения (и продолжаю это делать при использовании механизма доступа к данным ADO), а теперь перенес его в модуль данных:

procedure TDataModule1.DataModuleCreate(Sender: TObject);
var
    iniF: TIniFile;
    sDriver, sServer, sPort, sUser, sPassword: string;//Параметры строки подключения к данным
begin
    //Считываем данные из файла Config.
    //Для этого создаем объект файла Конфиг
    iniF:=TiniFile.Create(sTekPapka+'\Config.ini');
    //Считываем содержимое файла Конфиг и присваиваем их переменным,
    //чтобы дальше подставить их в строку подключения.
    sDriver:=iniF.ReadString('DB', 'Driver','');
    sServer:=iniF.ReadString('DB', 'Server','');
    sPort:=iniF.ReadString('DB', 'Port','');
    sUser:=iniF.ReadString('DB', 'User','');
    sPassword:=iniF.ReadString('DB', 'Password','');
    iniF.free;
    FDConnection1.Close;//Закрываем соединение с БД
    with FDConnection1.Params do
    begin
       Clear;
       Values['DriverID']:='ODBC';
       Values['ODBCDriver']:=sDriver;
       Values['Host']:=sServer;
       Values['Port']:=sPort;
       Values['User_Name']:=sUser;
       Values['Password']:=sPassword;
       Values['Database']:='signs';
    end;
    try
       FDConnection1.Connected:=true;// Открываем соединение
    except
       Application.CreateForm(TfrmConnection,frmConnection);
       frmConnection.Show;
    end;
end;

В этом примере параметры подключения хранятся в файле Config.ini, который у меня выглядит следующим образом:

[ORG]
NameOrg=Название организации
UrAdres=Адрес организации
Telefon=Телефон организации
[DB]
Driver=MySQL ODBC 8.0 Unicode Driver
Server=Localhost
Port=3306
User=root
Password=1234

Собственно, за подключение здесь отвечает секция DB. Параметры подключения очень удобно хранить в INI-файлах. После того, как мы взяли все эти параметры, мы их присвоим строковым переменным. Ну а дальше открываем соединение.

Если, допустим, в строке подключения будет не верное имя пользователя или пароль, то будет создана форма frmConnection, где мы сможем указать правильные параметры для нашего подключения.

Ну вот, собственно, пожалуй и все по данной теме. Таким образом, проблему с ошибкой «Access violation at adress...» будет решена.

Понравилась статья? Поделиться с друзьями:
Добавить комментарий

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!: