Configurando e usando o MySQL Embedded
Escrito por Carlos B. Feitoza Filho | |
Categoria: Artigos | |
Categoria Pai: Addicted 2 Delphi! | |
Acessos: 12758 |
Tenho visto atualmente algumas pessoas necessitarem de bancos de dados de configuração zero para distribuir juntamente com seus executáveis. Apesar de existirem atualmente soluções mais modernas e talvez melhores, eu quero apresentar algo que é extremamente funcional e que pode ser usado de forma local para substituir um servidor MySQL com todos os seus recursos[1]. Trata-se do MySQL Embedded, ou em português, MySQL Embutido (ou embarcado).
O MySQL Embedded trata-se basicamente da dll do servidor MySQL (libmysqld.dll) que é carregada pelo seu programa e que o torna, grosso modo, em um servidor MySQL completo, mas de acesso restrito, apenas a própria aplicação que carregou a dll é capaz de acessar um banco de dados gerenciado por ela. A vantagem mais evidente do MySQL Embedded sobre os atuais bancos "light", seria a curva de aprendizado. Se você já trabalha com MySQL ou qualquer outro banco de dados relacional, você já sabe como usar o MySQL Embedded, simplesmente porque ele funciona como qualquer banco de dados relacional! As consultas SQL que você executa no MySQL Embedded são aquelas que você executaria em um servidor MySQL tradicional.
Mão na massa
O exemplo o qual vou descrever a seguir, e que encontra-se anexado a este artigo, usa o FireDAC, mas também é possível fazer a mesma coisa com o ZeosLib e provavelmente outros componentes de conexão. Obviamente cada componente de conexão tem formas distintas de utilizar o MySQL Embedded e cabe a você pesquisar sobre como usá-lo nestes componentes.
Como de costume, eu vou exibir a minha forma de fazer isso, usando nomenclaturas e estruturas de diretórios que eu acredito serem adequadas. Boa parte do que eu vou mostrar pode ser modificado por você a fim de adequar a implementação ao seu sistema, contudo eu não vou dar maiores detalhes de como fazer isso simplesmente porque eu não quero. Encare isso como uma forma de forçar você, caro leitor, a procurar outros recursos mais detalhados pela web.
Chega de conversa e vamos ao que interessa. Crie uma aplicação vazia e inclua 1 x TDataModule. No TForm existente inclua 3 x TButton, 1 x TMemo e 1 x TDBGrid. Você pode usar a imagem abaixo como exemplo:
No TDataModule inclua 1 x TFDPhysMySQLDriverLink, 1 x TFDConnection, 1 x TFDGUIxWaitCursor, 1 x TFDQuery e 1 x TDataSource.
Após a inclusão destes componentes é hora de configurar uma estrutura de diretórios básica. Você vai precisar de alguns arquivos do MySQL, os quais você pode conseguir diretamente em seu site (https://dev.mysql.com/downloads/mysql/). Baixe a versão em ZIP do MySQL e não a versão instalável. Certifique-se também de estar baixando a versão com a arquitetura adequada ao seu sistema (32 ou 64 bits). Caso queira baixar a mesma versão usada no exemplo anexado, ela está aqui.
O arquivo ZIP tem cerca de 300MB, mas não se preocupe, você não vai usar tudo que está no ZIP. O MySQL Embedded limpo (sem banco de dados) possui cerca de 20MB[2]. Um tamanho razoável de distribuição, se você considerar que você tem todo o poder do MySQL em seu sistema, sem ter tido que instalar nada, mas mesmo assim eu considero essa uma desvantagem do MySQL Embedded: ele não é muito econômico em termos de espaço. Após primeira conexão com o banco de dados, a pasta do MySQL Embedded vai ter cerca de 110MB!! Mesmo não sendo algo light como os modernos bancos embarcáveis, eu continuo vendo utilidade para o MySQL Embedded e recomendo a leitura completa deste artigo.
Crie um estrutura de diretórios tendo como raiz uma pasta de nome "database", na mesma pasta onde vai ficar o executável de sua aplicação. Se seu executável estiver, por exemplo, em C:\Meu Programa, crie a pasta database dentro de C:\Meu Programa, de forma que, dentro da mesma haja a seguinte estrutura de diretórios:
Configurando o FireDAC
A configuração do FireDAC é simples, no entanto existem alguns detalhes importantes que precisam ser mencionados e que valem para qualquer configuração que for utilizada, são eles:
- Todos os argumentos que são paths precisam usar barras normais, no padrão Unix (/)
- Você pode usar caminhos completos ou preferencialmente caminhos relativos à pasta onde o seu executável se encontra
- A biblieteca libmysqld.dll e os arquivos de mensagens (errmsg.sys) precisam ser da mesma versão, portanto, ao atualizar a biblioteca, lembre-se de trocar todos os arquivos de mensagens também
- A versão 5.1.34 da biblioteca libmysqld.dll, e provavelmente outras versões, são bugadas e não funcionam para instanciar o MySQL Embedded. Caso você tenha seguido à risca este artigo e mesmo assim sua implementação não funcionar, primeiramente verifique os argumentos e caso todos estejam corretos, considere trocar a versão de libmysqld.dll por alguma outra. A versão utilizada por mim ao fazer este artigo foi a 5.7.18
- Caso os argumentos de inicialização de libmysqld.dll sejam usados de forma incorreta, a aplicação poderá ser finalizada sem aviso
Para replicar o exemplo anexado a este artigo, prossiga da forma apresentada a seguir. Todos os argumentos apresentados devem ser colocados na propriedade TFDPhysMySQLDriverLink.EmbeddedArgs. Tenha isso em mente sempre que for falado em "adicionar um argumento". Não vou ficar repetindo essa informação a fim de favorecer a legibilidade:
- No ZIP do MySQL, a partir de sua pasta lib, copie o arquivo libmysqld.dll para dentro da pasta database. Esta dll É o servidor MySql, o qual estará trabalhando de forma restrita, onde apenas sua aplicação conseguirá acessá-lo;
- Adicione o argumento --basedir=./database. Note que ./ indica sempre o diretório onde o executável de sua aplicação está, logo, este argumento aponta para a pasta "database" que está dentro da mesma pasta onde o seu executável está;
- Configure a propriedade TADPhysMySQLDriverLink.VendorLib para ./database/libmysqld.dll. Essa propriedade informa qual dll o nosso programa irá carregar;
- No ZIP do MySQL, entre na pasta share e copie as pastas charsets, english e portuguese dentro da pasta share da estrutura de diretórios que você criou anteriormente. A pasta charsets contém xmls de definição e mapeamento de vários conjuntos de caracteres que o MySQL poderá usar. Como estes arquivos são pequenos eu recomendo que todos eles sejam copiados. As pastas english e portuguese contém apenas um arquivo cada, de nome errmsg.sys. Este arquivo contém todas as mensagens de erro que o MySQL emite. Eu incluí neste exemplo o inglês e o português, mas você poderia copiar somente um dos dois ou qualquer uma das outras linguagens contidas na pasta share. O MySQL usa um, e apenas um, arquivo de mensagens de erro durante sua execução;
- Selecione a linguagem das mensagens que o MySQL vai emitir, adicionando o argumento --language=portuguese (para mensagens em português) ou --language=english (para mensagens em inglês). O nome que aparece após o sinal de igualdade é o nome da pasta que contém o arquivo errmsg.sys com as mensagens no idioma indicado, logo, estas pastas precisam existir dentro do diretório share. Caso você queira usar um outro idioma, simplesmente adicione a pasta com as mensagens do idioma escolhido à pasta share e altere o argumento para o nome da pasta com o idioma pretendido;
- Adicione o argumento --datadir=./database/data. Este argumento indica o diretório que vai conter efetivamente a estrutura e os dados de todos os esquemas que forem criados no MySQL Embedded. Caso precise fazer um backup do(s) banco(s) de dados, é esta pasta que precisa ser guardada e recuperada posteriormente;
- Caso não queira usar a engine InnoDB, você pode usar o argumento --skip-innodb, mas caso queira usá-la, inclua o argumento --innodb_data_home_dir=./database/data. Não é obrigatório que este diretório seja o mesmo diretório do argumento --datadir, no entanto, a fim de facilitar um possível backup futuro, é melhor que todos fiquem juntos;
- Se você não deseja permitir que seu programa acesse um servidor MySQL remoto, inclua o argumento --skip-networking. Esse argumento garantirá que seu programa use apenas o MySQL Embedded. Caso você não inclua este argumento, o seu programa poderá realizar conexões a outros servidores MySQL tradicionais, usando a biblioteca libmysqld.dll como biblioteca cliente;
- Se você precisa usar plugins do MySQL, no ZIP do mesmo, entre na pasta lib\plugin, e copie as bibliotecas (dll) dos plugins que deseja usar para uma pasta criada abaixo da pasta database, por exemplo, database\plugin e inclua o argumento --plugin_dir=./database/plugin. A fim de tornar nosso exemplo mais leve e simples, nenhum plugin está sendo utilizado;
- Você pode adicionar alguns dos argumentos listados em https://dev.mysql.com/doc/refman/5.7/en/server-options.html a fim de ajustar o comportamento de sua instância do MySQL Embedded. Nem todos eles fazem sentido para este modo de uso do MySQL, no entanto, alguns deles podem ser usados para, digamos, melhorar o desempenho.
Após realizar estas configurações exclusivas do MySQL Embedded, você pode configurar o TFDConnection. Chamar de configuração é um exagero, já que a única coisa a ser feita é indicar o Driver ID como sendo MySQL. Veja a imagem abaixo:
Como se pode observar, nada mais precisa ser alterado. Não é necessária qualquer informação de login ou servidor porque o acesso é restrito. Você ficaria tentado a clicar o botão "Test" a fim de realizar uma conexão, mas logo notará que isso não é possível. A seguinte mensagem de erro vai aparecer, caso você clique este botão:
Esta mensagem de erro é mais clara do que parece. A fim de tornar a implementação do programa mais simples, todos os caminhos são relativos ao diretório do executável, no entanto, ao executar uma conexão a partir da IDE do Delphi, este caminho fica relativo ao diretório de onde está o executável do Delphi (bds.exe), logo, nenhum dos caminhos é válido.
Caso queira realizar conexões em tempo de projeto, você deve usar caminhos completos em todas as configurações de caminhos que foram citadas neste artigo. Isso eventualmente pode quebrar seu programa ao executá-lo, portanto, tenha cuidado e altere os caminhos para caminhos relativos em tempo de execução. Você pode utilizar o evento TFDConnection.BeforeConnect e reconfigurar todos os caminhos.
Conclusão
É óbvio que devem haver soluções que consomem menos espaço em disco. Talvez as soluções mais modernas sejam até mais eficientes em outros aspectos, mas, como eu disse anteriormente, esta técnica de usar o MySQL embutido em uma aplicação Delphi pode ter sua utilidade e merece ser conhecida por todos. Eu imagino que hajam argumentos que podem ser utilizados para diminuir este consumo de espaço em disco, mas eu não conheço todos, e por isso cabe a você, leitor, estudar o conteúdo de https://dev.mysql.com/doc/refman/5.7/en/server-options.html.
1 | Na verdade existem algumas limitações, mas são limitações que nem se aplicam em um banco entendido para ser de uso exclusivo de uma única aplicação. Caso queira ver a lista completa de limitações do MySQL Embedded, clique aqui |
2 | Ao conectar-se ao MySQL Embedded alguns arquivos padrão, referentes ao "information schema", serão criados. Além disso, o banco de dados que você criar, bem como todos os seus objetos (tabelas, views, triggers, procedures, etc.) também ocupam espaço, logo, o requisito de espaço para sua aplicação final, compilada e rodando será aumentado de 20MB para um valor que vai variar, dependendo do quão grande seu banco de dados embutido seja. |