Arquivo da tag: Java

Conhecendo o Liquibase

Introdução

Iniciado em 2006, o Liquibase é uma biblioteca que conta com documentação completa e de fácil entendimento, com isso, utilizá-lo não exige uma curva de aprendizado muito grande, tornando ele bastante atrativo. Seu uso, tende oferecer muito ganho em produtividade oferecendo a possibilidade de disponibilização de uma base de dados funcional, atualizada e compatível com a qualquer versão de sua aplicação em um ambiente de desenvolvimento ou testes em poucos minutos.
Porém, o principal objetivo do Liquibase é facilitar a rastreabilidade de alterações executadas no banco de dados, para isso, faz uso de um versionamento altamente poderoso, descomplicado e semelhante ao encontrado em ferramentas de controle de versão de código, como por exemplo, SVN e GIT.  Além disso, ele não se limita apenas ao controle de versão, sendo também, uma poderosa ferramenta de migração e refatoração do banco de dados.
Para tornar possível o gerenciamento do banco de dados, o Liquibase faz uso de um arquivo XML denominado changelog. Neste arquivo, são concentradas informações sobre o histórico de evolução do banco de dados e, um exemplo disso são instruções SQL executadas ou pendentes para uma determinada base de dados. O changelog pode ser composto por um ou vários changesets, que, ao fazer analogia com um sistema de controle de versão do código, poderíamos dizer que o changelog corresponderia a uma branch e os changesets aos commits.
Além do changelog, o Liquibase também faz uso de duas tabelas denominadas: databasechangelog e databasechangeloglock, estas, são criadas no banco de dados a partir da primeira execução. Sempre que executado, o Liquibase fará uma comparação entre as instruções contidas no changelog com registros da tabela databasechangelog, desta forma, ele consegue identificar o que precisa ser executado para tornar o banco de dados compatível com a versão atual do sistema.
Neste artigo, os exemplos serão apresentados apenas utilizando a sintaxe do formato XML, porém, desde o seu lançamento o Liquibase está em constante evolução e, a partir da versão 3.x foram introduzidos novos formatos com sintaxes específicas para o changelog dando suporte as extensões: XML, JSON, YAML ou SQL.
A execução do Liquibase pode ser feita de duas formas, a primeira é conhecida como On Demand, sendo esta, por linha de comando, Maven ou Ant Builder. A segunda é a automatizada, podendo ser por: Servlet Listener, Spring Listener ou JEE CDI Listener.
Independente da sua opção não existe restrição para execução das principais funcionalidades do Liquibase, sendo: Update, Rolback, Diff, SQL Output e DB Doc.

Configuração

Para trabalhar com o Liquibase na versão 3.x é necessário utilizar Java 6 ou superior. Porém, também é possível utilizar a versão 2.x que neste caso tem como requisito Java 5 ou superior.
O primeiro passo é fazer o download do JAR no site oficial do projeto. Aqui optei por utilizar a versão 3.4.2 publicada em 24/11/2015. Obs: Atualmente a biblioteca possui versões mais recentes.
Após concluir o download, caso não tenha optado por executar o Liquibase via linha de comando, poderá incluir o JAR: liquibase-core-3.4.2.jar juntamente com o driver do banco de dados no classpath do seu projeto. Caso sua opção seja executar via linha de comando, copie os arquivos para um diretório de sua preferência.
Para este artigo optou-se pelo uso PostgresSql versão 9.5, sendo assim, o driver utilizado foi o: postgresql-9.1-901.jdbc3.jar

CHANGELOG

O changelog é o arquivo XML onde deverão ser registradas as instruções DDL e DML que serão executadas no banco de dados. A partir deste arquivo, o Liquibase consegue fazer a verificação de estado do banco de dados e executar somente instruções ainda pendentes.
O Exemplo 01 apresenta um exemplo padrão de changelog no formato xml. Nele encontram-se declarados os namespaces necessários para validação do arquivo na versão 3.4.x.

Exemplo 01

<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
     xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
     xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
     http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.4.xsd
     http://www.liquibase.org/xml/ns/dbchangelog-ext
     http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd">
</databaseChangeLog>

Como boa prática, é sugerida a criação de vários arquivos changelogs e, que em cada arquivo sejam concentradas as alterações necessárias para o banco de dados em um determinado release ou branch. Com isso, além de se obter um histórico mais preciso e detalhado sobre alterações efetuadas no banco, merges se tornam mais fáceis em caso de conflitos, uma vez que, o changelog de uma versão ou release, tende conter uma quantidade menor de instruções.
Seguindo esta dica, pode ser criado um arquivo xml, aqui chamado de changelog-master e, nele será incluído o caminho completo de cada changelog existente.
O Exemplo 02 apresenta a criação deste arquivo, que conta com a inclusão de dois arquivos changelog.

Exemplo 02

<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" 
     xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext" 
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
     xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog 
     http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.4.xsd 
     http://www.liquibase.org/xml/ns/dbchangelog-ext 
     http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd">

    <include file="changelog-1.0.xml" />
    <include file="changelog-2.0.xml" />

</databaseChangeLog>

Como dito anteriormente cada arquivo changelog pode conter um conjunto de changesets que é o seu principal elemento.
O Exemplo 03 apresenta a estrutura básica de criação do changeset contendo os atributos obrigatórios, sendo: id e autor. Importante: Para o Liquibase é importante que o id tenha valor único por autor e changelog.
Os valores definidos para cada um destes atributos serão persistidos no banco de dados após a execução. Estas informações são utilizadas para identificar changesets já aplicados e pendentes em uma determinada base de dados.

Exemplo 03

<changeSet author="NOME_DO_AUTOR" id="VALOR_UNICO">
   // Instruções
</changeSet>

Nota: Cada desenvolvedor é responsável incrementar o id e inserir identificação no changeset. O Liquibase, apenas validará se está pendente execução e o aplicará no banco de dados registrando para que não seja executado novamente.
O Liquibase fornece uma estrutura sintática simplificada e semelhante a uma instrução SQL para ser usada no changeset.
O Exemplo 04 apresenta uma instrução de criação de uma tabela para armazenamento de cidades.  Note que sintaxe proposta pelo Liquibase se assemelha a uma instrução SQL.

Exemplo 04 

<changeSet author="DESENVOLVEDOR" id="1">
     <createTable tableName="CIDADE">
          <column autoIncrement="true" name="ID" type="BIGSERIAL">
               <constraints primaryKey="true" primaryKeyName="ID_CIDADE "/>
          </column>
          <column name="NOME" type="VARCHAR(255)"/>
          <column name="ID_ESTADO" type="INT"/>
     </createTable>
</changeSet> 

O Liquibase também fornece a opção de criação de instruções no formato SQL, para isso, pode-se utilizar um bloco CDATA.
Exemplo 05 apresenta uma instrução para criação de uma function exemplificando este cenário.

Exemplo 05 

<changeSet author="DESENVOLVEDOR" id="2">
     <sql splitStatements="false"><![CDATA[
          CREATE OR REPLACE FUNCTION SUM(IN VALOR1 INTEGER, IN VALOR2 INTEGER)
          RETURNS INTEGER AS 
          $BODY$BEGIN
          RETURN VALOR1 + VALOR2;
          END;$BODY$
          LANGUAGE PLPGSQL;
     ]]></sql>
</changeSet> 

Nota: Ao criar utilizar um bloco CDATA para instruções SQL, as particularidades de cada banco devem ser levadas em consideração, como no exemplo, o valor LANGUAGE PLPGSQL.

TABELAS DO LIQUIBASE

Para atingir o objetivo a que se propõe, o Liquibase faz uso de duas tabelas, sendo: databasechangelog e databasechangeloglock.
A primeira tabela é onde serão armazenadas as informações referentes a instruções, DDL ou DML descritas em cada changeset. Sempre que um changeset é executado com sucesso, um novo registro será inserido nesta tabela.
Exemplo 06 apresenta o código SQL de criação da tabela databasechangelog e a seguir são detalhados alguns dos campos existentes nesta tabela. 

Exemplo 06

CREATE TABLE databasechangelog(
     id character varying(255) NOT NULL,
     author character varying(255) NOT NULL,
     filename character varying(255) NOT NULL,
     dateexecuted timestamp without time zone NOT NULL,
     orderexecuted integer NOT NULL,
     exectype character varying(10) NOT NULL,
     md5sum character varying(35),
     description character varying(255),
     comments character varying(255),
     tag character varying(255),
     liquibase character varying(20),
     contexts character varying(255),
     labels character varying(255)
);

Os campos id e autor correspondem aos valores informados nos respectivos atributos encontrados no changeset.
O campo filename é utilizando para armazenar o nome do arquivo do qual o changeset está incluso.
Com base na informação contida nos campos id, autor e filename, o Liquibase irá gerar um hash e o campo md5sum é onde esta informação fica armazenada.

Nota: O campo md5sum é utilizando para identificar cada changeset já aplicado no banco dados, com isso, após aplicar um changeset, este não poderá sofrer qualquer tipo de alteração. Por exemplo, para a criação de uma determinada tabela foi criado um changeset contendo o id 1 no changelog-1.0.xml cujo autor foi o desenvolvedor1. Após concluir a execução, o desenvolvedor1 identificou que um campo da tabela foi criado com o tipo de dado errado e, para corrigir este problema o optou por efetuar a alteração no changeset que já havia sido executado. Ao executar novamente o Liquibase irá gerar um novo hash devido à alteração e ao comparar com md5sum persistido pela primeira execução, um erro será lançado.
Este comportamento é realmente o esperado, pois, em um cenário real quando algo do tipo ocorre em um versionador de código fonte, não é possível alterar um commit já efetuado e sim criar um novo comit para a correção do problema. Sendo assim, neste cenário, a correção deverá ocorrer por meio de uma instrução alter table em um novo changeset.
O Exemplo 07 apresenta a estrutura da tabela databasechangeloglock. Esta tabela, é utilizada para tratamento de concorrência. Quando se inicia sua execução um lock e feito no banco de dados e somente é desfeito após a sua conclusão.

Exemplo 07

CREATE TABLE public.databasechangeloglock(
     id integer NOT NULL,
     locked boolean NOT NULL,
     lockgranted timestamp without time zone,
     lockedby character varying(255),
     CONSTRAINT pk_databasechangeloglock PRIMARY KEY (id)
);

O campo locked é utilizado para identificar o estado atual da base dados podendo receber o valor “T” quando um lock é feito e “F” quando é desfeito.
Se durante uma execução ocorrer um problema, a base de dados permanecerá no estado locked, que poderá ser revertido de forma manual por meio de uma instrução de update nesta coluna ou por um comando de rollback.
O campo lockedby indicará o nome e ip da maquina de onde se originou a execução do Liquibase.

EXECUÇÃO

Linha de Comando

Para executar o Liquibase via linha de comando, é necessário juntar em um diretório de sua preferência o JAR do Liquibase e o driver do banco de dados.
A execução pode ser feita de duas formas. Em uma delas, os parâmetros a serem considerados para cada comando a ser executado são inseridos diretamente no prompt conformo apresentado no Exemplo 08.

Exemplo 08

java –jar liquibase.jar -–driver=org.postgresql.Driver --classpath=postgresql-jdbc-driver.jar
–-changeLogFile=changelog.xml --url="jdbc:postgresql://localhost:5432/xpto"
--username=usuario --password=senha update

Esta forma se torna pouco praticável devido à quantidade de parâmetros que varia de acordo com o comando desejado.
Outra forma, seria criar no mesmo diretório de arquivos do Liquibase um arquivo de propriedades denominado liquibase.properties e nele definir os parâmetros necessários para sua execução conforme apresentado no Exemplo 09 

Exemplo 09

classpath: postgresql-9.1-901.jdbc3.jar
driver: org.postgresql.Driver
url: jdbc:postgresql://localhost:5432/xpto
username: usuario
password: senha
changeLogFile=changelog.xml

Após a criação deste arquivo, a execução do comando se dá conforme Exemplo 10

 Exemplo 10

java –jar liquibase.jar update
 

Servlet Listener

Utilizando esta opção, Liquibase irá aplicar as instruções contidas no changelog durante o deploy da aplicação. Para isso, é necessário incluir alguns parâmetros de contexto no Web Descriptor (web.xml). O Exemplo 11 demostra os parâmetros necessário e que serão detalhados na seqüência.

Exemplo 11

<context-param>
     <param-name>liquibase.changelog</param-name>
     <param-value>com/example/db.changelog.xml</param-value>
</context-param>
<context-param>
     <param-name>liquibase.datasource</param-name>
     <param-value>java:comp/env/jdbc/default</param-value>
</context-param>
<context-param>
     <param-name>liquibase.host.includes</param-name>
     <param-value>production1.example.com, production2.example.com</param-value>
</context-param> 
<context-param>
     <param-name>liquibase.onerror.fail</param-name>
     <param-value>true</param-value>
</context-param> 
<context-param>
     <param-name>liquibase.contexts</param-name>
     <param-value>production</param-value>
</context-param> 
<listener>
     <listener-class>liquibase.integration.servlet.LiquibaseServletListener</listener-class>
</listener>
  • liquibase.changelog – Caminho para localização dos changelogs.
  • liquibase.datasource  – Caminho para localização do datasource. Caso o usuário do banco de dados utilizado pela aplicação não tenha os privilégios necessários para criar, alterar ou deletar tabelas no banco de dados, uma opção, seria criar um novo usuário para o Liquibase que contenha estes privilégios, desta forma, não obrigando ser o mesmo usuário da aplicação.
  • liquibase.host.includes – Configurações para hosts onde se deseja que o Liquibase seja executado. Pode ser útil quando se possui clientes onde por definição de compliance, somente DBAs podem aplicar scripts no banco de dados. Esta configuração, irá garantir que o Liquibase não seja executado em determinadas bases de dados.
  • liquibase.onerror.fail – Configurações para que o Liquibase tome alguma ação caso ocorra alguma exceção. Tal configuração é importante para garantir o estado do banco de dados quando um erro surgir durante a implantação.
  • liquibase.contexts – Configuração do contexto para aplicação. Caso exista uma lista de contextos, estes, podem ser declarados separando-os por vírgula.
  • Listener – ServletListener responsável pela inicialização do Liquibase durante o deploy da aplicação.

Spring Framework

Para integração entre o Liquibase e o Spring, é necessário a criação de um Bean no contexto do Spring. O Exemplo 12 apresenta um exemplo completo de criação deste Bean e propriedades necessárias para configuração.

Exemplo 12

<bean id="liquibase" class="liquibase.integration.spring.SpringLiquibase">
     <property name="dataSource" ref="myDataSource" />
     <property name="changeLog" value="classpath:db-changelog.xml" />
     <property name="contexts" value="test, production" />
</bean>
  • Datasource: Caso já exista um Data Source basta fazer referência.
  • Path: Declaração do caminho onde está localizado o arquivo changelog.
  • Contexto: Declaração dos contextos onde se deseja que o Liquibase seja executado.

Maven Plugin

Com Maven é possível executar o Liquibase durante o processo de build. Para isso, é necessário declarar um plugin no arquivo POM do projeto.
Esta configuração pode ser feita de duas formas, a primeira declarando os parâmetros necessários para a execução do Liquibase diretamente no corpo do plugin e a segunda, externalizando os parâmetros. O Exemplo 13 apresenta a configuração do plugin utilizando um arquivo de propriedades externo.

Exemplo 13

<project>
     <build>
          <plugins>
               <plugin>
                    <groupId>org.liquibase</groupId>
                    <artifactId>liquibase-maven-plugin</artifactId>
                    <version>3.0.5</version>
                    <configuration>
                         <propertyFile>src/main/resources/liquibase/liquibase.properties</propertyFile>
                    </configuration>
                    <executions>
                         <execution>
                              <phase>process-resources</phase>
                              <goals>
                                   <goal>update</goal>
                              </goals>
                        </execution>
                   </executions>
             </plugin>
        </plugins>
     </build>
</project>

O Exemplo 14 apresenta o arquivo liquibase.properties, contendo os parâmetros para execução do liquibase via plugin.

Exemplo 14

contexts: test
changeLogFile: com/company/client/project/db.changelog.xml
driver: org.postgresql.Driver
url: jdbc:postgresql://localhost:5432/xpto
username: usuario
password: senha

O Exemplo 15 apresenta a declaração do plugin contendo os parâmetros declarados diretamente em seu corpo

<plugin>
     <groupId>org.liquibase</groupId>
     <artifactId>liquibase-maven-plugin</artifactId>
     <version>3.0.5</version>
     <configuration>
         <changeLogFile>src/main/resources/org/liquibase/changelog.xml</changeLogFile>
         <driver> org.postgresql.Driver</driver>
         <url> jdbc:postgresql://localhost:5432/xpto </url>
         <username>user</username>
         <password>password</password>
     </configuration>
     <executions>
          <execution>
               <phase>process-resources</phase>
               <goals>
                    <goal>update</goal>
               </goals>
          </execution>
     </executions>
</plugin>

Alterações e Refatorações

O Liquibase fornece uma estrutura sintática para criação de instruções SQL simplificada. A seguir serão apresentados exemplos de uso de algumas das principais instruções utilizadas no cotidiano de um desenvolvedor executadas a partir do comando update cuja execução se da conforme apresentado no Exemplo 10.

Create Table

Comando utilizado para criação de tabelas, o Exemplo 16 demostrar a criação de duas tabelas, sendo a primeira a tabela para armazenar os Estados e a segunda as Cidades.

Exemplo 16

<changeSet author="Fernando" id="1">
     <comment>Criação da tabela de Estado</comment>
     <createTable tableName="estado">
          <column autoIncrement="true" name="id" type="SERIAL">
               <constraints primaryKey="true" primaryKeyName="pk_estado_id"/>
          </column>
          <column name="nome" type="VARCHAR(25)"/>
          <column name="sigla" type="CHAR(2)"/>
    </createTable>
</changeSet>
<changeSet author="Fernando" id="2">	
     <comment>Criação da tabela de Cidade</comment>
     <createTable tableName="cidade">
          <column autoIncrement="true" name="id" type="SERIAL">
               <constraints primaryKey="true" primaryKeyName="pk_cidade_id"/>
          </column>
          <column name="nome" type="VARCHAR(80)"/>
          <column name="populacao" type="NUMERIC"/>
          <column name="gentilico" type="VARCHAR(250)"/>
          <column name="area" type="NUMERIC"/>
     </createTable>
</changeSet>

Após a execução o Liquibase irá popular a tabela databasechangelog com informações referentes às instruções envolvidas em cada changeset. A Imagem 1 apresenta os dados constantes na tabela.

Imagem 1

 

Nota: Para a apresentação de resultados, algumas colunas ficaram ocultas com o objetivo de facilitar a visualização do conteúdo na imagem.

Insert

Comando utilizado para popular tabelas no banco de dados, o Exemplo 17 apresenta o uso deste comando utilizando para inserir dados nas tabelas criadas no Exemplo 16.

Exemplo 17

<changeSet author="Fernando" id="3">
     <comment>Inserindo o estado Paraná</comment>
     <insert tableName="estado">
          <column name="sigla" value="PR" />
          <column name="nome" value="Paraná" />
     </insert>
</changeSet>
<changeSet author="Fernando" id="4">
     <comment>Inserindo a cidade Maringá</comment>
     <insert tableName="cidade">
          <column name="nome" value="Maringá" />
          <column name="populacao" value="385.753" />
          <column name="gentilico" value="Maringaense" />
          <column name="area" value="487.9" />
     </insert>
</changeSet>

A Imagem 2 apresenta os resultados da tabela datatabasechangelog atualizados.

Add Column

Comando utilizado para adição de colunas a uma determinada tabela do banco de dados. O Exemplo 18 apresenta um exemplo de uso deste comando aplicado na criação da coluna estado na tabela cidade.

Exemplo 18

<changeSet author="Fernando" id="5">
     <comment>Adição da coluna id_estado </comment>
     <addColumn tableName="cidade">
          <column name="id_estado" type="INT"/>
     </addColumn>
</changeSet>
[/sourcecode language="xml"]>

<h4>Alter Table</h4>

Comando utilizando para criar relacionamento entre tabelas, o <strong>Exemplo 19</strong> apresenta uso deste comando na criação da foreign key  entre as tabelas cidade e estado.

<strong>Exemplo 19</strong>


<changeSet author="Fernando" id="5">
     <comment>Criação da Foreign Key</comment>
     <addForeignKeyConstraint constraintName="fk_estado"
          baseTableName="cidade" baseColumnNames="id_estado"
          referencedTableName="estado" referencedColumnNames="id"/>
</changeSet>

SQL

Também é possível executar instruções SQL dentro de um changeset. O Exemplo 20 apresenta um exemplo deste comando utilizado para executar o update na tabela Cidade inserindo o id do estado a partir de uma instrução select.

Exemplo 20

<changeSet author="Fernando" id="6">
     <comment>Referenciado cidade Maringá com Estado Paraná</comment>
     <sql>
          UPDATE cidade
          SET id_estado = (SELECT id FROM estado WHERE sigla = 'PR')
          WHERE nome = 'Maringá';
     </sql>
</changeSet>

Preconditions

O Liquibase também oferece a opção para definição de condições para execução de um determinado comando no banco de dados. O Exemplo 21 apresenta o exemplo de uma instrução de insert que somente será executada caso a condição dada seja cumprida.
Para atributo onFail apresetado na Linha 2, os seguintes valores poderão ser utilizados:
HALT: Este é o valor default, usado para indicar um erro durante a execução, o que fará com que o Liquibase se encerre imediatamente não executado changesets declarados posteriormente.
CONTINUE: Usado para indicar que caso ocorra um problema a execução de um determinado changeset, o Liquibase deverá pular para o próximo changeset. Desta forma não será registrado na tabela databasechangelog, fazendo com que o Liquibase tente executar novamente sempre que for inicializado. O Liquibase irá registrar a execução deste changeset na tabela databasechangelog, caso a condição se atenda em algum momento.
MARK_RAN: semelhante ao comportamento definido pela flag CONTINUE, no entanto o Liquibase registrará o changeset como MARK_RAN na tabela databasechangelog, desta forma não tentará mais executar em suas próximas inicializações.
WARN: O Liquibase irá emitir apenas um alerta, porém sua execução ocorrerá normalmente mesmo que um erro ocorra.

Exemplo 21

<changeSet author="Fernando" id="7">
     <preConditions onFail="CONTINUE">
          <sqlCheck expectedResult="1"> SELECT count(*) FROM estado WHERE sigla = 'SP' </sqlCheck>
     </preConditions>
     <comment>Adicionando a cidade de São Paulo</comment>
     <insert tableName="cidade">
          <column name="nome" value="São Paulo" />
          <column name="populacao" value="11967825" />
          <column name="gentilico" value="Paulista" />
          <column name="area" value="1521.110" />
     </insert>
     <sql>
          UPDATE cidade
          SET id_estado = (SELECT id FROM estado WHERE sigla = 'SP')
          WHERE nome = 'São Paulo';
     </sql>
</changeSet>

Uma prática bastante interessante de uso para precoditions é validação do banco de dados antes da execução de uma determinada instrução. Para isso pode-se usar a tag dbms informando o nome banco de dados no atributo type. O Exemplo 22 apresenta um exemplo de como utilizar este comando.

Exemplo 22 

<preConditions>
     <dbms type="oracle" />
</preConditions>

Ao adicionar esta precondition no inicio do changelog, é possível garantir que a execução do Liquibase está condicionada ao uso do banco de dados Oracle, como para este artigo optou-se pelo uso do PostgreSql, ao executar o comando de update do Liquibase, o seguinte erro seria retornado: “DBMS Precondition failed: expected oracle, got postgresql”, com isso, nenhuma instrução contida no changelog deverá ser executada no banco de dados.
Além do oracle, o Liquibase também também esta apto a trabalhar com os seguinte bancos: mysql, postgresql, mssql, sybase, asany, db2, derby, hsqldb, informix, firebird, sqlite.

Load Data

O Liquibase fornece também uma forma de carregamento de arquivos para o banco de dados. Por exemplo, para popular as tabelas Cidade e Estado, podem ser utilizados arquivos no formato csv contendo os registros a serem importados. O Exemplo 23 apresenta um exemplo de uso deste comando.

Exemplo 23

<changeSet author="Fernando" id="8">
     <comment>Carregando arquivo csv para o banco de dados</comment>
     <loadUpdateData primaryKey="id" tableName="estado" file="estados.csv" separator=";">
          <column name="id" type="NUMERIC"/>
          <column name="nome"  type="STRING" />
          <column name="sigla" type="STRING"/>
     </loadUpdateData >
     <update tableName="cidade">
          <column name="id_estado" value="18"/>
          <where>nome = 'Maringá'</where>
     </update>
</changeSet>

Custon Change

Esta opção se torna excelente para refatoração do banco de dados. Por exemplo, imagine um cenário onde optou-se por mesclar os dados das tabelas cidade e estado em uma única tabela, para isso criou-se uma nova tabela denominada cidade_temp que recebera alguns dados existentes nas tabelas cidade e estado.
Utilizando a tag customChange, é possível fazer a copia dos dados para a nova tabela utilizando uma classe Java. O Exemplo 24 apresenta o exemplo para declaração da tag custonChange linhas 12 a 15 e o Exemplo 25 apresenta a classe Java contendo a implentação para efetuar a cópia dos dados.

Exemplo 24

<changeSet author="Fernando" id="9">
     <comment>Criação da tabela cidade_temp</comment>
     <createTable tableName="cidade_temp">
          <column autoIncrement="true" name="id" type="SERIAL">
               <constraints primaryKey="true" primaryKeyName="pk_cidade_temp_id" />
          </column>
          <column name="cidade" type="VARCHAR(80)" />
          <column name="estado" type="VARCHAR(25)" />
     </createTable>
</changeSet>
<changeSet author="Fernando" id="10">
     <comment>Copia de dados de cidade e estado</comment>
     <customChange class="br.fernandogodoy.CidadeTemp"></customChange>
</changeSet>

Exemplo 25

public class CidadeTemp implements CustomTaskChange{
     @Override
     public String getConfirmationMessage() {
          return "Dados copiados com Sucesso!";
     } 
     @Override
     public void setFileOpener(ResourceAccessor arg0) {}
     @Override
     public void setUp() throws SetupException { }
     @Override
     public ValidationErrors validate(Database arg0) { return null; }
     @Override
     public void execute(Database database) throws CustomChangeException {
          try {
               JdbcConnection connection = (JdbcConnection) database.getConnection();
               ResultSet resultSet = connection.createStatement().executeQuery(
                    "SELECT c.nome, e.nome, e.sigla " +
                    " FROM cidade c, estado e WHERE c.id_estado = e.id");
               while (resultSet.next()) {
                    String nome   = resultSet.getString(1);
                    String estado = resultSet.getString(2);
                    String sigla  = resultSet.getString(3);
                    String estadoStr = estado + ", " + sigla;
                    PreparedStatement ps = connection.prepareStatement(
                         "INSERT INTO cidade_temp(cidade, estado) VALUES(?, ?)");
                    ps.setString(1, nome);
                    ps.setString(2, estadoStr);
                    ps.execute();
                }
               resultSet.close();
         } catch (DatabaseException | SQLException e) {
               throw new CustomChangeException("Ocorreu um erro: ", e.getCause());
         }
     }
}

Drop

Comando utilizado para dropar foreign key, colunas, indice, constraints, primary key, procedures, sequences, tables, e views.
O Exemplo 26 apresenta o uso do comando drop table para deleção das tabelas cidade e estado.

Exemplo 26

<pre><code><changeSet author="Fernando" id="11">
     <comment>Dropando tabela estados</comment>
     <dropTable cascadeConstraints="true" schemaName="public" tableName="estado"/>
</changeSet>
<changeSet author="Fernando" id="12">
     <comment>Dropando tabela cidade</comment>
     <dropTable cascadeConstraints="true" schemaName="public" tableName="cidade"/>
</changeSet>

Rename

Comando utilizado para renomeação de tabelas, colunas e view. O Exemplo 27 apresenta um exemplo de uso deste comando aplicado na tabela cidade_temp.

Exemplo 27

<changeSet author="Fernando" id="13">
     <renameTable newTableName="cidade" oldTableName="cidade_temp" schemaName="public"/>
</changeSet>

Geração de Changelog

Além do comando para aplicar alterações no banco de dados, o Liquibase também oferece um comando responsável por fazer o papel inverso, ou seja, exportar a estrutura de uma base de dados para um arquivo changelog por meio do comando generateChangelog.
Exemplo 28 apresenta o comando generateChangelog e a Exemplo 29 apresenta o resultado da execução. Neste exemplo será utilizado o mesmo arquivo de propriedades criadas no Exemplo 09, a diferença é que o atributo changeLogFile possui um papel diferente neste cenário.
Para o comando update ele é utilizado para indicar qual arquivo changelog contém os changesets aplicados ou pendentes execução no banco de dados. Já no comando generateChangeLog ele indicará o nome do arquivo irá conter o resultado da exportação.

Exemplo 28

java –jar liquibase.jar generateChangeLog

Exemplo 29

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
             xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext
             http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd
             http://www.liquibase.org/xml/ns/dbchangelog
             http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.4.xsd">
     <changeSet author="Fernando (generated)" id="1462859827908-1">
          <createSequence sequenceName="cidade_temp_id_seq"/>
     </changeSet>
     <changeSet author="Fernando (generated)" id="1462859827908-2">
          <createTable tableName="cidade">
               <column autoIncrement="true" name="id" type="SERIAL">
                    <constraints primaryKey="true" primaryKeyName="pk_cidade_temp_id"/>
               </column>
               <column name="cidade" type="VARCHAR(80)"/>
               <column name="estado" type="VARCHAR(25)"/>
          </createTable>
     </changeSet>
</databaseChangeLog>

Diff

Embora não seja o propósito do Liquibase, sentiu-se a necessidade de efetuar comparação de bases de dados. Para isso foi disponibilizado o comando diff, porém como descrito na própria documentação da ferramenta, este comando é falho por dos motivos e deve ser utilizado com cuidado.
A primeira falha do diff é que assim como acontece no SVN, ele efetua apenas a análise sintática do banco dados, um exemplo disso acontece quando fazemos a renomeação de uma tabela ou coluna. Ao executar comando diff, o Liquibase irá apontar que um item foi removido e um novo foi criado exatamente por não saber diferenciar semanticamente as alterações.
A segunda falha está ligada a informações que podem influênciam no funcionamento da aplicação, uma vez que, o diff não compreende a exportação de dados.
Portanto ao usar o diff, deve-se ter o cuidado de analisar calmamente os resultados apresentados para evitar perca de informações.
O Exemplo 30 apresenta o arquivo de propriedades contendo os parâmetros necessários para a comparação e o Exemplo 31 apresenta o comando a ser executado

Exemplo 30

classpath: postgresql-9.1-901.jdbc3.jar
driver=org.postgresql.Driver
url=jdbc:postgresql://localhost:5432/artigo
username=postgres
password=admin
referenceUrl=jdbc:postgresql://localhost:5432/artigoex
referenceUsername=postgres
referencePassword=admin

Exemplo 31

java –jar liquibase.jar diff > diff.log

Como resultado, o Liquibase deverá gerar um relatório conforme apresentado no Exemplo 32.

Exemplo 32

Diff Results:
Reference Database: postgres@jdbc:postgresql://localhost:5432/artigoex (Default Schema: public)
Comparison Database: postgres@jdbc:postgresql://localhost:5432/artigo (Default Schema: public)
Product Name: EQUAL
Product Version: EQUAL
Missing Catalog(s): NONE
Unexpected Catalog(s): NONE
Changed Catalog(s):
artigoxe
name changed from 'artigoex' to 'artigo'
Missing Column(s): NONE
Unexpected Column(s):
cidade.cidade
cidade.estado
cidade.id
Changed Column(s): NONE
Missing Foreign Key(s): NONE
Unexpected Foreign Key(s): NONE
Changed Foreign Key(s): NONE
Missing Index(s): NONE
Unexpected Index(s):
pk_cidade_id unique  on cidade(id)
Changed Index(s): NONE
Missing Primary Key(s): NONE
Unexpected Primary Key(s):
pk_cidade_id on cidade(id)
Changed Primary Key(s): NONE
Missing Schema(s): NONE
Unexpected Schema(s): NONE
Changed Schema(s): NONE
Missing Sequence(s): NONE
Unexpected Sequence(s): cidade_id_seq
Changed Sequence(s): NONE
Missing Stored Procedure(s): NONE
Unexpected Stored Procedure(s): NONE
Changed Stored Procedure(s): NONE
Missing Table(s): NONE
Unexpected Table(s): cidade
Changed Table(s): NONE
Missing Unique Constraint(s): NONE
Unexpected Unique Constraint(s): NONE
Changed Unique Constraint(s): NONE
Missing View(s): NONE
Unexpected View(s): NONE
Changed View(s): NONE

Além do relatório de diferenças o Liquibase também possibilita que seja gerado o changelog a partir do comando diffChangeLog. O Exemplo 32 apresenta o uso deste comando e o Exemplo 33 apresenta o resultado da execução.

Exemplo 32

java –jar liquibase.jar diffChangeLog > diff.xml</code

Exemplo 33

<changeSet author="Fernando (generated)" id="1463634090806-1">
     <createSequence sequenceName="cidade_id_seq"/>
</changeSet>
<changeSet author="Fernando (generated)" id="1463634090806-2">
     <createTable tableName="cidade">
          <column autoIncrement="true" name="id" type="SERIAL">
               <constraints primaryKey="true" primaryKeyName="pk_cidade_id"/>
          </column>
          <column name="cidade" type="VARCHAR(80)"/>
          <column name="estado" type="VARCHAR(25)"/>
    </createTable>
</changeSet>

DBDoc

Outra funcionalidade interessante existente no Liquibase é o DBDoc, com este, é possível criar uma documentação bastante completa para o banco de dados em um padrão semelhante ao JavaDoc.
O Eemplo 34 apresenta o comando utilizado para geração do DBDoc onde “doc/dbdoc” será o diretório para geração dos arquivos e a Imagem 3 apresenta o resultado após a geração.

Eemplo 34

java –jar liquibase.jar dbdoc doc/dbdoc

Conclusão

Este artigo abordou alguns dos comandos e funcionalidade do Liquibase para reastreabilidade e aplicação de alterações em banco de dados. Ao que se propõe, o Liquibase demonstra ser uma das ferramentas mais poderosas existentes no mercado.
Uma das vantagens de se usar o Liquibase é que além da quantidade de comandos e funcionalidade já existentes, seu código fonte é open source, o que permite a quem o utiliza, customizar comandos e adequar a sua realidade, tornando assim o framework flexível e adaptável.

Referências

Download Liquibase: http://www.liquibase.org/download/
Documentação: http://www.liquibase.org/documentation/index.html
O Problema de Versionamento do Banco de Dados: https://dicasdolampada.wordpress.com/2012/03/15/o-problema-do-versionamento-do-banco-de-dados/
Evoluindo o Banco de Dados com Liquibase: https://dicasdolampada.wordpress.com/2012/03/19/evoluindo-o-banco-de-dados-com-o-liquibase/
Liquibase: Gerenciamento de Alteração em banco de dados: http://www2.dc.ufscar.br/~paulo.papotti/material_liquibase.pdf
Liquibase With Maven: http://www.yegor256.com/2014/07/20/liquibase-in-maven.html
Managing your Database Migrations using Liquibase: https://blog.codecentric.de/en/2015/01/managing-database-migrations-using-liquibase
Liquibase – Open Source Tool for Database Version Control: http://www.methodsandtools.com/tools/tools.php?liquibase
Automated Liquibase Generator And Validator(ALGV): http://www.ijstr.org/final-print/sep2015/Automated-Liquibase-Generator-And-Validatoralgv.pdf
Liquibase Introduction: http://mmstratton.com/wp/liquibase-introduction/
Banco de Dados Evolutivo: https://arthurluz.wordpress.com/tag/liquibase/

Spring MVC com Annotations – Configurando a Camada de Persistência

Fala pessoal, tudo bem?

Passando para compartilhar mais uma publicação minha no blog da MATERA Systems da série de posts sobre configuração do Spring sem XML.

Neste post, explico como configurar a camada de persistência(sem xml, é claro).

Link: http://www.matera.com/br/2016/10/24/spring-mvc-com-annotations-configurando-a-camada-de-persistencia/

Fico por aqui, espero que gostem e até breve.

 

Spring Framework com Annotations

Fala pessoal, tudo bem com vocês?

No ultimo Post falei sobre como podemos usar os benefícios da Injeção de Dependências (DI) e Inversão de Controle (IoC) utilizando o Spring Framework no desenvolvimento de aplicações Java na plataforma SE.

Porém ficou aquela coisa no ar que sempre deixa alguns programadores com receio de utilizar um determinado framework e essa coisa se chama configuração utilizando arquivo xml. A utilização do arquivo xml não é um problema para muitos, mais convenhamos, é um processo verboso e nem todos ficamos a vontade com o uso do arquivo xml.

Se você também pensa assim, que tal se fosse possível configurar o Spring Framework utilizando apenas anotações? Seria incrível livrar-se do xml não? Pois bem, a partir da versão 3.0 do Spring Framework isso já é possível com a anotação @Configuration.

Para isso basta ter uma classe conforme abaixo.

@Configuration
public class Context {

}

 

Simples não? Ao criar uma classe Java e adicionar a anotação @Configuration, estamos dizendo ao container do Spring que está classe pode ser utilizada com um “fornecedor” de Beans.

Até ai tudo bem, criei uma classe Java e adicionei a anotação, você deve ter pensado, e meus Beans? Como eu digo pro Spring Framework quem ele deve registrar?

Se vocês se lembra no arquivo xml, usávamos o  “context:component-scan” para dizer ao Spring em quais pacotes ele deveria procurar nosso beans e registrá-los.

Isto agora é feito da seguinte forma:

@Configuration
@ComponentScan (basePackages = "br.springannotations.*")
public class Context {

}

Feito isso, já temos o contexto do Spring Framework configurado, basta iniciar a aplicação e carregar o contexto para ver a mágica acontecer.

public static void main(String[] args) {

    ApplicationContext context = new AnnotationConfigApplicationContext(Context.class);
    UsuarioController bean = context.getBean(UsuarioController.class);
    bean.testController();
}

Com isso encerro por aqui, estou compartilhando o link do projeto no GitHub caso queiram ver mais detalhes.

Até a próxima.

Dependências

 

Referências

http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/

Projeto Java Desktop com Maven 4º Post

Olá,

Projetinho parado há algum tempo devido a falta de tempo, mais vamos dar sequência para concluir.

Pra inicio, criei um JFrame dando o nome de Principal.

Como o nome já diz, esta será nossa tela principal do sistema, ela que será aberta quando nosso sistema for inicializado.

Para ela não irei fazer nada muito difícil, inseri somente uma barra de menu com dois itens.

Ficando da seguinte forma.

Image

Para a opção Estado do menu, criei um JDialog dando o nome de EstadoForm.

Para ele também nada excepcional, dois campos de texto e um menu com as opções novo, salvar, editar e excluir.

Resumindo nosso formulário ficou da seguinte forma.

Image

Como todos sabem Java é uma linguagem que trabalha com Orientação a Objetos.

Pensando toda nossa tela se torna um objeto assim como cada item da nossa tela também se torna um objeto.

Por enquanto vamos pensar em nossos botões e por sinal temos quatro.

Se cada botão é um objeto, significa que cada um terá um comportamento.

Ps.: Se você pensou que nem todo objeto tem um comportamento, acredite ficar parado sem fazer nada por incrível que pareça é um comportamento.

Em Java, comportamentos são implementados criando-se métodos.

Passo inicial seria pensarmos nas ações que devem ocorrer quando ocorrer um click no botão Novo.

Primeiro passo seria habilitar os campos para preencher e já vamos garantir que estes campos estejam limpos para que nosso usuário preencha com os dados que quiser.

Vamos criar dois métodos separados para executar esta ação.

Se você pensou por que dois métodos separados a explicação mais simples para isto seria a seguinte.

Como estamos utilizando componentes Swing, tais componentes possuem nativos a implementação de um Listener (ouvinte) para eventos, ou seja, um click, o apertar uma tecla, etc.

Para este caso estaremos criando um evento para o click no botão que criamos.

Para fazer isto, click com botão direito do mouse sobre nosso botão > action > actionPerformed.

A ferramenta irá gerar o seguinte método.

private void jButtonActionPerformed(java.awt.event.ActionEvent evt) {  }

Nosso trabalho agora será implementar o comportamento desde método, uma vez que quando o usuário efetuar um click em nosso botão, o Listener saberá que é este método que deve ser executado.

Voltando agora na parte em que disse que criaríamos dois métodos separados para cara ação.

Para as duas ações em específicas que seria habilitar e limpar, e tais ações são bem genéricos e podem ser reutilizadas pra vários outros botões, então dentro dos métodos que indicará qual será a ação de nosso botão, apenas incluímos a chamada para nossos dois métodos, ficando da seguinte forma.

private void jButtonActionPerformed(java.awt.event.ActionEvent evt) {

habilitar(true);

limpar();

//demais métodos

}

Como o foco deste post é somente fazer um exemplo bem simples dando os conceitos básicos para quem esta iniciando com Java encerro por aqui.

Abraço e até mais.

O projeto completo ficará disponível no Git Hub.

Projeto Java Desktop com Maven 3º Post

Olá galera,

Para este post estarei criando nossas entidades para damos inicio a parte legal do projeto.

Bom como disse é sistema vai ser algo bem simples e por se tratar de algo que servirá de estudos para iniciantes em programação vamos fazer um cadastro de cidades e estados.

Particularmente não faço este tipo de cadastro em nenhum de meus sistemas, deixar com que o usuário efetue tal tipo de cadastro pode gerar inconsistência no banco de dados, pois, damos ao o usuário o poder de cadastrar cidades e estados que não existem, além de cidades em estados errados. Exemplo claro, o usuário por engano cadastrar Porto Alegre no estado de São Paulo, isto seria um problema e tanto não dando nenhuma credibilidade a informações que nosso sistema fornecerá. Neste caso prefiro inserir cidades e estados diretamente no banco evitando este tipo de problema. Pense pelo seguinte é muito difícil surgir estados e cidades novas do dia pra noite e caso surgir, não é nada fora do comum inserir diretamente no banco um estado e cidade nova. Lembrando opinião particular todo caso gera exceções, por isso analisem bem sua regra de negocio antes de sair criando classes e programando.

Dando sequencia e começando pela entidade estado.

No pacote br.com.meuprimeroprojeto.modelo, vamos criar uma nova classe Java e dar nome a ela de Estado.

Primeiro passo e o mais importante, definir os atributos que nosso estado irá ter. No nosso caso, nome e sigla ficando conforme abaixo.


package br.com.meuprimeiroprojeto.modelo;

/**
*
* @author Fernado
*/

public class Estado {
private Long idEstado;
private String nome;
private String sigla;
}

Feito isso criaremos uma nova classe Java e daremos o nome a ela de Cidade. No caso, somente o nome, porém aqui entra uma coisa interessante. Java é uma linguagem orientada a objetos, para quem não intende orientação a objetos lei este POST, acredito que irá ajudar. Neste caso já possuímos um objeto Estado e se formos pensar, toda cidade fica dentro de um Estado certo?

Neste caso nossa classe cidade ficará da seguinte forma.

package br.com.meuprimeiroprojeto.modelo;

/**
*
* @author Fernado
*/

public class Cidade {
private Long idCidade;
private String nome;
private Estado estado;
}

Bem como o post não ficou extenso vamos fazer o mapeamento objeto relacional das classes pra que o Hibernate crie as tabelas de nosso banco de dados.

Para fazer o mapeamento usaremos algumas Annotations.

Vamos lá:

@Entity: Informa que a classe mapeada é persistente

@Id: Definição de chave primária.

@GeneratedValue: Permite a geração de forma automática para o valor identificador baseados nos mecanismos de geração automática que existem no Hibernate. @GeneratedValue(strategy=”GenerationType.IDENTITY”)  Para este estou utilizando o mecanismo de geranção IDENTITY que é utilizada pra criar colunas identidades na maioria dos bancos de dados, porém existem outros, como SEQUENCE, INCREMENT, AUTO e TABLE, basta escolher o que melhor se aplica ao seu caso.

@ManyToOne: Informa a cardinalidade de muitos para um ao banco de dados. Para mapearmos quando inserimos um objeto dentro de outro é necessário que se informe tal Annotation. Em nosso caso, temos um objeto Estado dentro do objeto Cidade, ao se utilizá-la estamos informando que existem muitas Cidades dentro de um Estado.

Obs: Fiz um breve comentário sobre as Annotations utilizadas neste post, caso queira saber mais recomendo pesquisar algo, existem deversas annotations criadas para facilitar o mapeamento objeto relacional entre outras coisas.

Feito isso basta irmos ao HibernateUtility que se no pacote útil e informar as classes que queremos que o Hibenate mapie para nós deixando o arquivo conforme abaixo.


package br.com.meuprimeiroprojeto.util;

import br.com.meuprimeiroprojeto.modelo.Cidade;
import br.com.meuprimeiroprojeto.modelo.Estado;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;

public class HibernateUtility {

private static final SessionFactory factory;
private static final ThreadLocal sessionThread = new ThreadLocal();
private static final ThreadLocal transactionThread = new ThreadLocal();

public static Session getSession() {
Session session = (Session) sessionThread.get();
if ((session == null) || (!(session.isOpen()))) {
session = factory.openSession();
sessionThread.set(session);
}
return ((Session) sessionThread.get());
}

public static void closeSession() {
Session session = (Session) sessionThread.get();
if ((session != null) && (session.isOpen())) {
sessionThread.set(null);
session.close();
}
}

public static void beginTransaction() {
Transaction transaction = getSession().beginTransaction();
transactionThread.set(transaction);
}

public static void commitTransaction() {
Transaction transaction = (Transaction) transactionThread.get();
if ((transaction != null) && (!(transaction.wasCommitted())) && (!(transaction.wasRolledBack()))) {
transaction.commit();
transactionThread.set(null);
}
}

public static void rollbackTransaction() {
Transaction transaction = (Transaction) transactionThread.get();
if ((transaction != null) && (!(transaction.wasCommitted())) && (!(transaction.wasRolledBack()))) {
transaction.rollback();
transactionThread.set(null);
}
}

static {
try {
factory = new Configuration()
/***POSTGRESQL***/
//                    .setProperty("hibernate.dialect", "org.hibernate.dialect.PostgreSQLDialect")
//                    .setProperty("hibernate.connection.driver_class", "org.postgresql.Driver")
//                    .setProperty("hibernate.connection.url", "jdbc:postgresql://localhost/meuprimeiroprojeto")
//                    .setProperty("hibernate.connection.username", "postgres")
//                    .setProperty("hibernate.connection.password", "postgres")
/***MYSQL***/
.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQLInnoDBDialect")
.setProperty("hibernate.connection.driver_class", "com.mysql.jdbc.Driver")
//CONFIGURAÇÃO DA BASE DE DADOS ** Verificar sempre Username e Password caso necessario alterar.
.setProperty("hibernate.connection.url", "jdbc:mysql://localhost/meuprimeiroprojeto")
.setProperty("hibernate.connection.username", "root")
.setProperty("hibernate.connection.password", "root")

//                    .setProperty("hibernate.connection.datasource", "jdbc/dbSGC") //data source (so pra aplicacao web e tem q configurar no tomcat)
.setProperty("hibernate.hbm2ddl.auto", "update")
.setProperty("hibernate.c3p0.max_size", "10")
.setProperty("hibernate.c3p0.min_size", "2")
.setProperty("hibernate.c3p0.timeout", "5000")
.setProperty("hibernate.c3p0.max_statements", "10")
.setProperty("hibernate.c3p0.idle_test_period", "3000")
.setProperty("hibernate.c3p0.acquire_increment", "2")
.setProperty("show_sql", "true")
.setProperty("use_outer_join", "true")
.setProperty("hibernate.generate_statistics", "true")
.setProperty("hibernate.use_sql_comments", "true")
.setProperty("hibernate.format_sql", "true")
//CLASSES PARA MAPEAMENTO
.addAnnotatedClass(Cidade.class)
.addAnnotatedClass(Estado.class)

.buildSessionFactory();
} catch (RuntimeException e) {
e.printStackTrace();
throw e;
}
}

public static void main(String [] args) {

}

}

Ao termino temos nossas classes com as devidas annotations ficarma da seguinte forma:

Classe Estado


package br.com.meuprimeiroprojeto.modelo;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

/**
*
* @author Fernado
*/
@Entity
public class Estado {

@Id
@GeneratedValue(strategy= GenerationType.IDENTITY)
private Long idEstado;
private String nome;
private String sigla;

//GETTERS E  SETTERS OMITIDOS

}
<pre>

Classe Cidade


package br.com.meuprimeiroprojeto.modelo;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;

/**
*
* @author Fernado
*/
@Entity
public class Cidade {

@Id
@GeneratedValue(strategy= GenerationType.IDENTITY)
private Long idCidade;
private String nome;
@ManyToOne
private Estado estado;

//GETTERS E  SETTERS OMITIDOS
}

Para concluir, basta abrir MySQL e criarmos um novo schema dando a ele o nome dele de meuprimeiroprojeto.

Com isso termino por aqui e até o próximo post.

Fiz algumas alterações no arquivo POM.xml estarei deixando disponivel o código no GITHUB

Projeto Java Desktop com Maven

Para este post estarei iniciando um projeto de aplicação desktop utilizando o Netbeans, Hibernate e o Maven.

Estarei utilizando neste projeto o padrão de persistência DAO (Data Access Object) por se tratar de algo bem simples. Ao término deste começarei um novo projeto utilizando EntityMannager e SpringFramework algo mais elegante.

Bom por que utilizar o Maven ?

O Maven é um framework que considero muito interessante, ele irá nos proporcionar um certo conforto no desenvolvimento do projeto, uma vez que ele será o responsável por gerenciar nossas dependências, e consequentemente nosso projeto inteiro. Como ele faz isso acho que ficará mais claro no andamento do projeto.
Para iniciar devemos primeiramente configurar o Maven em nossa máquina e no NetBeans, para isso recomendo ler o post do meu amigo Thiago Marques que explica passo a passo como fazer isso.

Próximo passo agora é a criação do projeto no netbeans.
Quem desenvolve projetos desktop está acostumado a criar um projeto simples, porém para utilizar o Maven temos uma pequena diferença.
No menu vamos em Arquivo > Novo Projeto.  Ou pelo atalho CTRL+SHIFT+N.
Iremos selecionar em categorias a opção MAVEN e em Projeto APLICATIVO JAVA.

Ficando como na figura abaixo.

Na próxima tela inserimos algumas informações de nosso projeto ficando da seguinte forma.

Para este projeto, por se tratar de algo bem simples estas informações acima não são de muita importância, mais para projetos futuros que envolvem um pouco mais de complexidade explicarei a importância de tais informações. Já de inicio digo que tais informações estarão incluídas no arquivo POM.xml que é nosso arquivo de configuração do Maven.

Terminado a estrutura de nosso projeto deverá ficar desta forma

Iremos excluir o pacote com.MeuPrimeroProjeto  existente no diretório Pacotes de códigos fonte e Pacote de teste, deixando nosso projeto da seguinte forma.

Ao término teremos nossa estrutura da seguinte forma:
Pacote de códigos-fonte – Onde serão inseridos os pacotes de nosso projeto, classes, interfaces e formulários e etc.
Pacote de testes – Caso utilize testes automatizados tudo relacionado a isso deve ser incluído neste pacote.
Dependências – Onde serão inseridas as bibliotecas do projeto.
Testar Dependências – Onde serão inseridas as bibliotecas de testes caso seja feitos testes automatizados.
Arquivos do Projeto – Onde fica o POM.xml que é nosso arquivo de configuração do Maven, nele serão declaradas nossas dependências do projeto, plugins para compilação e tudo mais. Entrarei em mais detalhes nos próximos posts.

Com isso termino por aqui este primeiro post de inicialização do nosso projeto, para o próximo post iniciarei a criação das classes formulários e interfaces, lembrando que disponibilizarei no GITHUB todo o código quer for gerado neste projeto.
Até mais.

Spring Framework

Olá galera, algum tempo sem postar nada devido a correria neste final de ano na faculdade, Artigos e TCC, axo que sabem como é. Bom resolvi deixar aqui pra vocês um post de um Artigo que fiz para  13º Semana da Informática na Unipar Paranavaí, que é a universidade onde estou concluíndo minha graduação, onde minha orientadora é a Prof. Késsia R. C. Marchi sem dúvida uma das melhores professoras que tive durante minha graduação.  Bom o Spring é uma das ferramentas que utilizo no desenvolvimento do software para meu TCC. O que escrevi é pouco perto da capacidade que esta ferramenta possui, porém o artigo era de 5 pagina então tive que limitar e resumir bastante coisa. Mais espero que gostem. O artigo está disponivel no site do enveto denominado Seinpar onde existem diversos outros artigos do pessoal que está concluíndo a graduação e que são super interessantes. Vale a pena dar uma conferida.

AUMENTO DE PRODUTIVIDADE NO DESENVOLVIMENO DE APLICAÇÕES EM JAVA COM SPRING FRAMEWORK
Fernando S. Godói¹, Késsia R. C. Marchi¹
¹Universidade Paranaense (UNIPAR)
Paranavaí – PR – Brasil
fernandogodoy_18@msn.com, kessia@unipar.br

Resumo. Este artigo traz uma breve descrição do Spring Framework, apresentando sua estrutura e fazendo uma breve descrição dos padrões de Inversão de Controle e Injeção de Dependência, explicando quais benefícios estes padrões proporcionam no desenvolvimento de aplicações em Java. Será aplicado o Spring framework no desenvolvimento de uma aplicação em Java com uso dos padrões de Inversão de Controle e Injeção de Dependência.

1. Introdução
Atualmente o Java é uma linguagem utilizada universalmente, e este sucesso se deu devido ao poder que a linguagem possui possibilitando ao programador trabalhar tanto em baixo quanto em alto nível.
Com o passar dos anos o a linguagem teve uma grande evolução e seguindo este caminho surgiu o J2EE atualmente JEE, com foco em sistemas corporativos. Um dos problemas encontrados na JEE, é que a maior parte dos softwares criados atualmente é de pequeno porte, com isso a utilização de EJBs (Entreprise Java Beans) se tornou inviável devido ao alto nível de complexidade para à implementação. [Calçado 2008]
O Spring framework é uma tecnologia que surgiu para resolver o problema da complexidade encontrada nos EJBs, sendo um framework que implementa os padrões de Inversão de Controle e Injeção de Dependência, juntamente os Patterns de Setter Injection e Constructor Injection, além de prover técnicas de boa programação fornecendo um modelo unificado e simples de programação, isto o tornou um sucesso em meio à comunidade de programadores, sucesso este, foi tão grande que na versão mais nova do JEE, diversas melhorias foram criadas baseadas no Spring. [Calçado 2008; Pacheco 2007]
Este trabalho tem como foco falar sobre o Spring, fazendo uma breve abordagem sobre os padrões de Inversão de Controle e Injeção de Dependência que fizeram do Spring um sucesso junto à comunidade de programadores e utilizar o Spring framework em uma aplicação desenvolvida em Java observando os reais benefícios e facilidade que o Spring proporciona ao programador.

2. Spring
Atualmente mantido pela empresa Interface21, o Spring é um framework que trás diversos benefícios as aplicações, aumentando a produtividade no desenvolvimento de aplicações além de promover um grande aumento de performance em tempo de runtime, e facilitar o trabalho com testes unitários. [Schittini 2011]
O Spring Framework é composto por recursos organizados em cerca de 20 módulos, tais módulos podem ser implementados separadamente ou em conjunto com outros, isto permite ao Spring ser aplicado nos mais variados tipos de aplicações, sendo estas de qualquer porte. [Calçado 2008; Johson 2011]
O Spring implementa dois padrões de grande sucesso na comunidade de programadores que são de Inversão de Controle e Injeção de Dependência, provendo sempre das boas técnicas de programação, sendo estas, baixo acoplamento e alta coesão. Com sua arquitetura baseada em POJOs (Plain Old Java Object), o principal objetivo do Spring é tornar as tecnologias existentes atualmente no mercado fáceis de serem utilizadas.[ Calçado 2008; Schitini 2011]
O Spring possui outro recurso interessante que é o Lazy Inicialization, este recurso permite ao Spring que carregue apenas os Beans solicitados. Desta forma a aplicação ganha em desempenho, pois caso um Bean esteja declarado no Contexto do Spring e não esta sendo utilizado, este não será carregado, sendo carregado somente quando for necessário. [Pacheco 2007]

2.1 Estrutura
A figura 1, apresenta os módulos do Spring framework separadamente, cada um destes módulos pode ser implementado separadamente ou em conjunto com outros.
Figura 1 – Módulos do Spring. (Johson 2011)

2.1.1. Core Container
Neste módulo estão localizadas as funcionalidades padrões do Spring. Nele esta o BeanFactory, sendo este uma implementação do padrão Factory. Este módulo é responsável por aplicar a Inversão de Controle e Injeção de dependência na aplicação. [Balani 2005; Johson 2011]
Fornece também um avançado mecanismo de configuração capaz de gerenciar qualquer tipo de objeto. [Balani 2005; Johson 2011]
No Core Container, fica localizado Context, onde é encontrado o arquivo de configuração do Spring, um arquivo XML denominado ApplicationContext, nele também estão inclusos os serviços como JNDI, EJB, e-mail, validação, funcionalidades de agendamento, internacionalização, entre outros. [Balani 2005; Johson 2011]

2.1.2. Spring AOP e Instrumentation
Este módulo integra as funcionalidades da AOP (Aspect Oriented Programming), podendo esta ser implementada diretamente no Spring. Com isso, permite-se que o gerenciamento de transações passa a ser controlado pelo framework sem necessidade de componentes EJB, além de definição de Pointcuts e Methods Interceptors. [Balani 2005; Carvalho 2006]

2.1.3. Spring Data Acess/Integration
Este módulo implementa uma camada de abstração que possui uma hierarquia simplificada de tratamento erros de exceções lançadas pelo banco de dados, minimizando a quantidade do código criado para interação com banco de dados. [Balani 2005; Carvalho 2006]
Possui também o modulo ORM que implementa a conexão com frameworks para persistência facilitando o trabalho com estes. [Balani 2005; Carvalho 2006]
No módulo Transactions o Spring trata do gerenciamento de transações para classes que implementem interfaces especiais e para todos POJOs existentes na aplicação. [Schitini 2011]

2.1.4. Spring Web
Este módulo tem como base o módulo de contexto de aplicação, desta forma o Spring suportar a integração com o Jakarta Struts, além de facilitar a manipulação multi-parte, pedido e parâmetros de ligação entre objetos, possui também a inicialização do Container IOC (Inverse Of Control) usando Listeners e um arquivo de configuração Web Application Context. [Balani 2005; Johson 2011]
No Spring Servlet se localiza uma implementação do MVC (Model-View-Control) em um padrão altamente configurável por interfaces estratégicas, separando a regra de negócio de paginas Web. [Balani 2005; Johson 2001; Schitini 2011]

2.1.5. Spring Test
O Spring conta com o módulo de testes, dando suporte para o trabalho com componentes JUnit ou TestNG, além de suportar objetos Mock que simulam o comportamento de objetos reais da aplicação, permitindo que seu código seja testado isoladamente. [Johson 2011; Schitini 2011]

3. Inversão de Controle
Inversão de controle é o nome dado a um padrão onde a chamada de métodos que geralmente é efetuada pelo programador passa a ser invertida, ou seja, efetuada por um container ou outro componente que possa tomar o controle sobre a execução, é como se o programador delegasse esta tarefa a um terceiro. [Wikipédia 2008 ; Weissmann 2010]
No Spring os objetos existentes são considerados Beans, e o Container do Spring é que fica responsável por gerenciar os Beans existentes, geralmente estes possuem dependência entre si que são definidas através de meta-dados.[Calçado 2008]
O BeanFactory permite a recuperação de objetos pelo nome, além de gerenciar os relacionamentos entre objetos. Suporta dois modos de objetos, sendo um deles o Singleton que fornece uma instancia compartilhada, e o Prototype que assegura que cada objeto recuperado crie um objeto independente. [Balani 2005]

4. Injeção de Dependência
A Injeção de dependência é um padrão que se relaciona com a Inversão de Controle. É um padrão utilizado quando é necessário manter o baixo acoplamento entre objetos em um sistema. [Schitini 2011]
A forma mais comum de se obter referencia a um objeto é por instanciação direta, isto em Java é feito pelo operado new. O problema de quando se aplica esta forma é quando surge a necessidade de efetuar alterações em um objeto, este tipo de implementação viola o principio do baixo acoplamento entre os objetos. [Calçado 2008]
No conceito da Injeção de Dependência, as dependências não são declaradas na programação como no método tradicional, elas passam a ser injetadas diretamente pelo container, sendo o único trabalho necessário, efetuar a declaração das dependências em um arquivo de configuração.[Calçado 2008; Schitini 2011]
Com Injeção de dependência o código tende a ficar mais limpo, desacoplamento, mais eficaz uma vez que os objetos são fornecidos com suas dependências, tornando-se mais fácil a realização de testes quando as dependências são interfaces ou classes abstratas. [Johson 2011]
O Spring suporta dois tipos de injeção de dependência sendo Constructor Injection e Setter Injection. No Constructor Injection se utiliza do próprio construtor da classe para que se efetue a injeção, podendo este construtor ter quantos parâmetros forem necessários. Para que a injeção seja efetuada basta que o construtor seja anotado com uma annotation @Autowired. Já no Setter Injection, se declara as dependências em métodos Setters, devendo-se utilizar o padrão de nomenclatura correto, e sendo necessário efetuar algumas configurações, podendo ser por XML ou por código. O Setter Injection é o padrão que geralmente é adotado por desenvolvedores. [Fowler 2004; Pacheco 2007]

5. Metodologia
Para este trabalho foi realizada extensa revisão bibliográfica em materiais como livros, artigos e sites da Internet. O passo posterior foi utilizar o Spring framework no desenvolvimento de uma aplicação em Java, observado os reais benefícios que ele oferece ao programador e a aplicação.

6. Conclusão
A utilização de frameworks em projetos de desenvolvimento de softwares se torna uma prática bastante interessante, quando se pratica as boas técnicas de programação. O Spring é um framework com um potencial indiscutível, e sua aplicação em projetos impacta em alto ganho de produtividade, possui módulos bastante completos para desenvolvedores de aplicações, e permite ao programador dedicar-se à implementação da regra de negócio deixando que o Spring se encarregue do resto do trabalho.
Outro pronto interessante do Spring é que ele facilita a criação de teste, e a combinação do Spring com outros frameworks de gerencia de projeto traz benefícios visíveis à aplicação, deixando ela com um código limpo, facilitando manutenções e aumentando o nível de confiabilidade do software.

Referências
Balani, N. (2005) “Introduction to the Spring Framework”. <http://www.ibm.com/developerworks/web/library/wa-spring1/&gt; acesso em 21 de junho 2011.
Calçado, P. (2008) “Curso Spring Framework”. <http://blog.flexdev.com.br/wp-content/uploads/spring/apostila-spring.pdf&gt; acesso em 20 de maio 2011.
Carvalho, M. (2006) “Spring Framework Introdução”. <http://www.imasters.com.br/artigo/4497/java/spring_framework_introducao/&gt; acesso em 19 de junho 2011.
Fowler, M. (2004) “Inversion of Control Containers and the Dependency Injection Pattern”. <http://www.martinfowler.com/articles/injection.html&gt; acesso em 20 de julho 2011.
Johson, R. et Al (2011) “Spring Reference”. <http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/htmlsingle/spring-framework-reference.html&gt; acesso em 17 de julho de 2011.
Pacheco, D. (2007) “Spring Framework 2.0 para Desenvolvimento de Aplicações em Java”. <http://pt.scribd.com/doc/18517573/Spring-Framework-20-Diego-Pacheco&gt; acesso em 24 de julho 2011.
Schitini, I. et Al. (2011) “Spring Framework”. <http://kenai.com/projects/pos-sistemas-java-jf/sources/pos-java-ufjf-2009-2011/content/02-Daves/SpringFramework.doc?rev=48&gt; acesso em 04 de junho 2011.
Weissmann, L. H. (2010) “Injeção de Dependência com Spring Framework”. <http://www.itexto.net/devkico/?p=859&gt; acesso em 26/07/2011.
Wikipédia. (2008) “Inversão de Controle”. <http://pt.wikipedia.org/wiki/inversao_de_controle/&gt; acesso em 19 de junho 2011.

O Slide da apresentação está diponível no SlideShare neste Link: Slide Apresentação Seinpar