Grails: aspectos interessantes na configuração de acesso a dados

Em diversas aplicações que trabalhei, o único arquivo de configuração que precisamos alterar é o DataSources.groovy. E sabe o que é mais interessante neste componente do framework? É um arquivo de configuração vivo!

Grails sempre me surpreende, até em sua configuração básica. Porém, antes de mostrar alguns aspectos pouco conhecidos deste arquivo, vou começar pelo básico.

DataSource.groovy: o básico

Localizado em seu projeto Grails no diretório grails-app/conf, este é o arquivo aonde devemos incluir as informações que precisaremos para que possamos acessar a base de dados aonde nossas classes de domínio serão persistidas.

Normalmente o arquivo é composto por três seções: dataSource, hibernate e environments. No momento em que criamos uma aplicação Grails com o comando grails-app, este arquivo é gerado com a aparência abaixo:


dataSource {
    pooled = true
    driverClassName = "org.hsqldb.jdbcDriver"
    username = "sa"
    password = ""
}
hibernate {
    cache.use_second_level_cache = true
    cache.use_query_cache = true
    cache.provider_class = 'net.sf.ehcache.hibernate.EhCacheProvider'
}
// environment specific settings
environments {
    development {
        dataSource {
            dbCreate = "create-drop" // one of 'create', 'create-drop','update'
            url = "jdbc:hsqldb:mem:devDB"
        }
    }
    test {
        dataSource {
            dbCreate = "update"
            url = "jdbc:hsqldb:mem:testDb"
        }
    }
    production {
        dataSource {
            dbCreate = "update"
            url = "jdbc:hsqldb:file:prodDb;shutdown=true"
        }
    }
}

Como pode ser visto, cada uma das seções que mencionei compreende um bloco de código, cuja utilidade básica de cada uma, a grosso modo, é a seguinte:

  • dataSource – Armazena as configurações que são comuns a todos os ambientes de execução (falarei mais sobre os ambientes de execução neste post)
  • hibernate – Contém informações específicas do Hibernate, como por exemplo se desejamos trabalhar com cache, expor comandos SQL, etc. Todas as configurações do Hibernate, que você normalmente incluiria no arquivo hibernate.cfg (ou no Spring) deste ORM entram neste bloco.
  • environments – Uma aplicação Grails comporta o conceito de ambientes de execução. No contexto deste arquivo, um ambiente representa uma configuração específica de acesso ao banco de dados. Por default, temos três ambientes: desenvolvimento (development), testes (test) e produção (production).

Como assim ambientes?

Como mencionei, Grails implementa o conceito de ambientes de execução. É comum que no ciclo de vida de uma aplicação esta possua três tipos de ambiente: aquele no qual a desenvolvemos (development), aquele no qual executamos nossos testes automatizados (test) e, finalmente aquele que realmente importa, que é o ambiente de produção (production).

Na realidade, como já escrevi neste blog anteriormente, podemos inclusive ter mais de três ambientes. É uma maneira interessante de se ter por exemplo uma base de dados apenas para a execução de testes, o que facilita demais a vida do desenvolvedor.

O mais interessante é que os ambientes de execução vão além da “mera” configuração de datasources. Você pode, por exemplo, criar um ambiente de execução adicional que encapsule lógica específica de um cliente seu (se sua empresa trabalha com o desenvolvimento de produtos, fica ai minha dica pra você ;) ).

Reaproveitando código – dataSource

A seção DataSource normalmente é mal compreendida por diversos iniciantes. A grosso modo, no entanto, esta é a parte da sua configuração que você deve usar para incluir os aspectos que serão comuns a todos os seus ambientes. Por exemplo: se todos usarem o MySQL como banco de dados, não é necessário redigitar estes dados em cada um dos ambientes, basta inserir estas configurações nesta seção, tal como no exemplo abaixo:

dataSource {
    pooled = true
    driverClassName = "com.mysql.jdbc.Driver"
}
hibernate {
    cache.use_second_level_cache = true
    cache.use_query_cache = true
    cache.provider_class = 'net.sf.ehcache.hibernate.EhCacheProvider'
}
// environment specific settings
environments {
    development {
        dataSource {
            url = "jdbc:mysql://mysql/desenvolvimento"
            username = "jacob"
            password = "lost"
        }
    }
    test {
        dataSource {
            url = "jdbc:mysql://mysql/tests"
            username = "Benjamin"
            password = "Linus"
        }
    }
    production {
        dataSource {
             url = "jdbc:mysql://mysql/production"
             username = "Jack"
             password = "Shephard"
        }
    }
}

E o dbCreate? (LEIA COM ATENÇÃO!)

A propriedade dbCreate é uma das mais úteis e perigosas do Grails. Nós a usamos para hibernate.hbm2ddl.auto, e pode receber os seguintes valores:

  • create – Cria toda a estrutura de banco de dados pra você no momento em que a aplicação for iniciada, e também apaga todos os dados contidos nas tabelas caso estas já existam.
  • create-drop – Funciona da mesma maneira que create. A diferença é que quando a aplicação é finalizada, todas as tabelas são destruídas.
  • update – Atualiza as tabelas do banco de dados. Caso estas não existam, são criadas. Se novos atributos forem incluídos em suas classes, estes serão refletidos em suas tabelas também. No entanto, algumas mudanças não serão efetuadas. Se você por exemplo tiver renomeado campos, por exemplo, o GORM não saberá como lidar com isto (não ocorrerão erros). É importante notar também que caso atributos sejam excluídos de suas classes de domínio, isto não implicará na remoção de campos nas tabelas relacionadas (ainda bem!).
  • validate – simplesmente verifica se as suas classes de domínio estão de acordo com as tabelas do banco de dados. Nenhuma alteração é feita no banco de dados.

Por medida de segurança, no ambiente de produção você deve simplesmente excluir esta propriedade. Assim não correrá o risco de acidentalmente apagar ou modificar uma estrutura de dados que já esteja sendo usada por seus usuários.

Agora, o aspecto “vivo” da configuração

Já reparou que o arquivo “DataSource.groovy” possui a extensão “.groovy”? Ao contrário da maior parte dos arquivos de configuração, algumas das configurações do Grails são na realidade scripts!

Sendo assim, caso seja necessário, você pode definir o funcionamento do seu ambiente não apenas declarativamente, mas também lógicamente. Este aspecto pode nos mostrar uma nova gama de possibilidades, como por exemplo configurar o seu sistema de acordo com variações do ambiente no qual este se encontra instalado.

Confuso? Então aqui segue um exemplo: suponha que você desenvolva produtos, e que não sabe de antemão qual a url de conexão com o banco de dados. Nesta nossa situação hipotética, a string de conexão com o banco de dados poderia ser uma variável de ambiente. Como você faria?

Bem, aqui segue um exemplo:

...
environments {
        ...
         production {
             url = System.getProperty("url_de_conexao_com_o_banco_de_dados")
         }
        ...
}

Na realidade, você pode incluir qualquer código groovy dentro do seu arquivo de configuração. Sendo assim, você poderia ter algo como o código abaixo também.

...
environments {
        ...
         production {
             def valor = null
             switch (System.getProperty("propriedade_qualquer") {
                  case "a": valor = "coisas da vida"
                  case "b": valor = "coisas da vida louca"
             }
             url = valor
             new pacote.qualquer.ClasseQualquer.executeMetodo()
         }
        ...
}

Como pode ser visto no exemplo, você pode inclusive, apesar de não ser recomendado, executar código de inicialização presente em outras classes dentro do seu ambiente de execução. De qualquer maneira, o simples fato de ser possível incluir lógica em um arquivo de configuração já é uma vantagem fascinante.

Um aspecto interessante a ser levado em consideração é que o DataSource.groovy é executado sequencialmente. Sendo assim, em uma configuração padrão, a seção dataSource é executada primeiro, para logo em seguida virem hibernate e environments. Mas sabe de uma coisa? Seu script pode também ser incluído FORA destes blocos e, ainda mais interessante: a ordem em que são declarados não faz diferença alguma.

Como uso JNDI?

A melhor opção, ao menos na minha opinião é, ao invés de incluir suas configurações de acesso ao BD no DataSources.groovy, usar o JNDI. Assim você transfere a responsabilidade pela configuração do pool e outros aspectos do acesso ao banco de dados para o responsável pela manutenção do seu servidor de aplicações. Além disto, também evita de ficar incluindo senhas e nomes de usuários em um arquivo que qualquer um possa ver. Nestes casos, usamos a propriedade jndiName, tal como no exemplo abaixo:

...
   production {
          jndiName = "meu_nome_jndi"
   }
...

É possível ter apenas um ambiente?

Para finalizar este post, uma possibilidade interessante, mas que, em minha opinião, deve ser evitada a qualquer custo. Suponha que por alguma “razão” sinistra, você não queira ter três ambientes distintos, mas apenas um. Como você faria?

Simples: como mencionei anteriormente, a seção dataSource contém o código que será reaproveitado por todos os seus ambientes, certo? Neste caso, basta excluir a seção enrivonments e incluir toda a sua configuração de acesso nesta seção, tal como no exemplo abaixo:


hibernate {
    cache.use_second_level_cache = true
    cache.use_query_cache = true
    cache.provider_class = 'net.sf.ehcache.hibernate.EhCacheProvider'
}
dataSource {
    pooled = true
    driverClassName = "com.mysql.jdbc.Driver"
    url = "jdbc:mysql://souLouco/mesmo"
    username = "maluco"
    password = "meio_burro_também"
}

Como pode ver, é possível, mas por favor, não faça isto ok?

Concluindo

Como diria o tio do Homem-Aranha, “com grandes poderes, vêm grandes responsabilidades”. É exatamente o que ocorre aqui. Apesar do framework te oferecer a possibilidade de tratar o arquivo de configuração de acesso ao BD como um script, e você poder até mesmo subverter o padrão e possuir apenas um ambiente, minha sugestão para você é que evite ao máximo possível estes recursos.

Não porque eles podem danificar seu banco de dados ou tornar sua aplicação um monstro, mas sim porque dificulta o entendimento de novos membros que venham a entrar em sua equipe. Afinal de contas, 99,9% dos programadores esperam o comportamento padrão do Grails, não um “arquivo de configuração vivo”, não é mesmo? Porém, se mesmo assim optar por usar estes recursos, faça o possível para documentar estas peculiaridades do seu sistema ok?

9 thoughts on “Grails: aspectos interessantes na configuração de acesso a dados

  1. Estava quase abandonando um projeto meu em Grails, mas seus artigos me fizeram mudar de idéia (pelo menos, por enquanto). Escolhi Grails pela “semelhança” e ligação com o Java somado com a possibilidade de trabalhar com sistemas legados (leia-se: chaves compostas) e obviamente pela facilidade de desenvolvimento. Mas quando estive no último Java One (feito pela Oracle) fiquei desapontado com as palestras – como é que o Grails (e o Groovy) que praticamente SALVAM o desenvolvimento WEB para a plataforma Java não são explorados em nenhuma apresentação ? Será que eu fiz a escolha errada ? Deveria ter estudado RoR ? Bem, de qualquer forma parabéns pelo seu excelente trabalho.

    Responda

    admin Reply:

    Oi Constantino, valeu pelo apoio.

    Bem: o que rola é o seguinte: no caso da JavaOne, você só vai ver realmente os frameworks que são desenvolvidos pela própria Oracle/Sun ou que são apoiados por esta.

    Dado que o Grails é baseado no Spring, que basicamente é concorrente do stack padraõ JEE, é mais que natural a ausência, muitas vezes por falta de interesse dos próprios desenvolvedores do framework.

    Agora, se é uma boa escolha Grails ou não, ai depende muito mais do seu projeto do que do ambiente comercial atual.

    Responda

  2. Fala Amigo!
    Procurando entender o ciclo de vida do grails cheguei ate voce.
    Eu gostaria de entender o ciclo, pois estou em duvida com a classe Config.groovy
    No meu caso, preciso fazer com que o log4j faça um arquivo de log por dia, com historico de 15 dias. Blz…
    Estou tentando mudar meus appenders para que, com a aplicação rodando, quando eu virar o dia do sistema operacional(linux aqui), um novo arquivo.log seja criado.
    Por enquanto não coloquei logica nos scripts e estou insistindo em encontrar uma solução simples, mas se não conseguir, creio que vou instalar um pligin para trabalhar com log4j.xml :(

    Pode dar um norte ? la no Config.groovy tem a “clausura” log4j{ }… como eu posso configurar para que na virada do dia um novo arquivo com prefixo do dia atual seja criado por exemplo ?

    valeu

    Responda

    admin Reply:

    Oi Julio, me procure por e-mail? loboweissmann@gmail.com

    Esta parte do Grails é nebulosa, mas estou pensando sinceramente em postar alguma coisa aqui no blog sobre o assunto.

    Responda

Leave a Reply

Your email address will not be published. Required fields are marked *