Professional Documents
Culture Documents
que representam a informao desejada. Por exemplo, no caso de atingido. Caso o elemento no exista no vetor, o valor null retor-
um aluno, deveriam haver atributos que representam os dados nado. J o mtodo inserir() simplesmente insere o item passado
de um aluno, como nome, endereo, entre outros; se fosse um por parmetro na primeira posio vazia do vetor.
produto, teramos atributos para a descrio, o preo, o prazo
de validade do produto, entre outros. Contudo, para simplificar
a apresentao dos mtodos de pesquisa neste artigo, apenas a
chave do item ser considerada.
public MeuItem(int chave) { Listagem 3. Implementao do mtodo de pesquisa sequencial com um vetor
this.chave = chave; no ordenado.
}
1. public class ArrayDic implements Dicionario {
@Override 2.
public int compara(Item it) throws Exception { 3. private final int TAM_MAX = 100;
if (it instanceof MeuItem) { 4. private final Item itens[];
if (chave < ((MeuItem) it).chave) return MENOR; 5. private int pos;
else if (chave > ((MeuItem) it).chave) return MAIOR; 6.
else return IGUAL; 7. public ArrayDic() {
} else throw new Exception(No possvel comparar itens de 8. itens = new Item[TAM_MAX];
tipos diferentes!); 9. pos = 0;
} 10. }
11.
} 12. public boolean estahCheia() {
13. return (pos == TAM_MAX);
14. }
A interface Dicionario especifica os mtodos que qualquer 15.
16. @Override
implementao de um dicionrio deve conter, ou seja, as 17. public Item pesquisar(Item it) throws Exception {
operaes de insero e pesquisa de elementos no mesmo. 18. for (int i = 0; i < pos; i++) {
A partir desta interface, diversas alternativas de implementao 19. if (itens[i].compara(it) == Item.IGUAL) {
20. return itens[i];
de um dicionrio podem existir utilizando listas encadeadas, 21. }
vetores, rvores, entre outros. Os tpicos Pesquisa Sequencial, 22. }
Pesquisa Binria e Pesquisa por Tabela Hash apresentam 23. return null;
24. }
algumas das possveis formas de se implementar um dicion- 25.
rio a partir da interface criada, discutindo seus pontos fortes 26. @Override
e desvantagens. 27. public void inserir(Item it) throws Exception {
28. if (!estahCheia()) {
29. itens[pos] = it;
Pesquisa sequencial 30. pos++;
31. } else {
A pesquisa sequencial um dos mtodos de pesquisa mais
32. throw new Exception(Capacidade mxima atingida!);
simples que existe. Ele funciona da seguinte forma: a partir do 33. }
primeiro registro (ou do ltimo), pesquisa sequencialmente at 34. }
35. }
encontrar a chave procurada ou at chegar ao final (ou ao incio)
do conjunto de registros.
A Figura 1 ilustra os passos da execuo da busca sequencial
para encontrar o elemento g no vetor [a, b, c, d, e, f, g, h]. Algumas caractersticas da estratgia de pesquisa sequencial
A implementao de um dicionrio para a pesquisa sequencial, so:
utilizando um vetor (array) de itens no ordenados, apresentada 1. Por se tratar de um vetor no ordenado, a insero de qualquer
na Listagem 3. Os mtodos mais importantes desta listagem so elemento feita de forma eficiente, inserindo-o sempre no final do
pesquisar() e inserir(). O primeiro retorna o registro do item vetor, com um custo computacional constante, isto , M(n) = 1;
passado por parmetro, caso ele exista no vetor denominado 2. O mtodo pesquisar() executa em tempo linear, realizando,
itens. Observa-se que a pesquisa ocorre elemento por elemento, no pior caso, C(n) = n comparaes para encontrar um elemento.
at o que o mesmo seja encontrado ou at que o final do vetor seja Para o caso mdio, C (n) = n + 1 .
2
Pesquisa binria por meio desses parmetros que o sistema controla qual parte
Como foi visto anteriormente, manter o vetor ordenado para do vetor deve ser analisada a cada passo.
realizao de uma pesquisa sequencial pode ser til, pois o tem-
po de execuo mdio para buscas sem sucesso cai pela metade. Listagem 7. Implementao do mtodo de pesquisa binria em um vetor.
Porm, o custo para a insero de um elemento em um vetor
1. private Item pesquisaRecursiva(Item it, int e, int d) throws Exception {
ordenado significativamente maior do que para a insero em 2. if (e > d) return null;
um vetor no ordenado. 3. int m = (e + d)/2;
Ainda sobre buscas, h um mtodo de pesquisa que pode utilizar 4. if (itens[m].compara(it) == Item.IGUAL) return itens[m];
5. else if (itens[m].compara(it) == Item.MENOR)
melhor a vantagem de termos um vetor ordenado para melhoria 6. return pesquisaRecursiva(it, m + 1, d);
do tempo consumido para localizar um elemento. Esse mtodo 7. else return pesquisaRecursiva(it, e, m - 1);
conhecido como pesquisa binria e ser descrito nesta seo. 8. }
9.
A ideia da pesquisa binria dividir o conjunto de itens em 10. @Override
duas partes, determinar em qual dessas duas partes o elemento 11. public Item pesquisar(Item it) throws Exception {
pesquisado pode pertencer e ento concentrar a busca apenas 12. return pesquisaRecursiva(it, 0, pos - 1);
13. }
nessa parte. A estratgia utilizada para resoluo deste proble-
ma conhecida como dividir para conquistar e est presente
em vrios tipos de algoritmos, como os de ordenao QuickSort, A funo pesquisaRecursiva() possui dois casos base: quando
MergeSort, entre outros. A ideia reduzir um problema maior, que o elemento encontrado (linha 4); e quando o valor do parmetro
no se sabe como resolver a priori, em problemas menores, para e maior do que o valor do parmetro d (linha 2), o que significa
os quais se conhece a soluo. Depois, utilizar tal soluo para que todo o vetor foi pesquisado e que o elemento procurado no
resolver o problema maior. se encontra nele. Como passos recursivos, h duas possibilidades.
A primeira ocorre quando a chave do elemento procurado maior
Pesquisa binria Implementao com Vetor do que a chave do elemento do meio do vetor (linha 5). Neste caso,
Para saber se um elemento pertence a um vetor utilizando a a funo pesquisaRecursiva() invocada recursivamente, mas
pesquisa binria, compara-se a chave deste elemento com a chave o vetor a ser considerado aquele que vai do ndice do elemento
do elemento que est no meio do conjunto (lembrando que o vetor do meio + 1 at o ndice do ltimo elemento do vetor original.
deve estar ordenado). Se a chave for igual procurada, ento a E a segunda possibilidade ocorre quando a chave do elemento
busca termina com sucesso; caso a chave seja menor, ento o ele- procurado menor do que a chave do elemento do meio do vetor
mento procurado deve estar na primeira parte do vetor (do incio (linha 7). Neste caso, a funo pesquisaRecursiva() tambm
at o elemento do meio - 1); se a chave for maior, ento o elemento invocada recursivamente, mas o vetor a ser considerado aquele
deve estar na segunda parte do vetor, que vai do elemento que que vai do ndice do primeiro elemento do vetor original at o
est aps o elemento do meio at o ltimo elemento. Esse mesmo ndice do elemento do meio 1.
procedimento descrito deve ser repetido na metade escolhida at A quantidade de comparaes realizadas pelo algoritmo de
que se encontre o elemento ou at que todos os elementos do vetor pesquisa binria dada por: C(n) = 1 + C(n/2). Isto , o nmero de
tenham sido investigados sem sucesso. comparaes realizadas pela pesquisa binria para um vetor de
A Figura 2 ilustra os passos da execuo de uma pesquisa binria tamanho n igual a uma comparao mais o custo de encontrar
para encontrar o elemento g no vetor [a, b, c, d, e, f, g, h]. o elemento na metade do vetor, que dado por C(n/2), o que leva
seguinte funo de complexidade: C (n) = lg n + 1 .
Isto quer dizer que, para casos de sucesso ou insucesso, a pesqui-
sa binria nunca executar em mais do que lgn + 1 passos, o que
um resultado significativamente melhor do que os resultados
do mtodo de pesquisa sequencial. Por exemplo, para n = 106, o
mtodo de pesquisa sequencial gastaria 106 passos no caso de uma
busca sem sucesso, uma vez que sua complexidade do pior caso
Figura 2. Ilustrao da execuo do mtodo de pesquisa binria proporcional a n. J o mtodo de pesquisa binria executaria em
lg106, que aproximadamente igual a 20.
O trecho de cdigo da Listagem 7 apresenta uma verso recur- Entretanto, importante levar em considerao o custo para
siva do mtodo de pesquisa binria. Como podemos verificar, o manter o vetor ordenado, isto , para cada insero de um novo
mtodo pesquisar() delega o trabalho de encontrar o elemento elemento. No pior caso, n movimentaes sero realizadas. Sendo
para a funo pesquisaRecursiva(). Esta recebe, alm do elemento assim, a busca binria, da maneira como foi implementada nesta
a ser pesquisado, dois parmetros inteiros e e d que correspondem, seo, deve ser utilizada em conjuntos pouco dinmicos, em que
respectivamente, aos ndices do primeiro e do ltimo elemento a quantidade de consultas realizadas seja bem maior do que a
do vetor que est sendo analisado no momento. quantidade de inseres feitas no conjunto de elementos.
formam um caminho partindo da raiz que, no pior caso, chega ao e movimentaes constante. Porm, esse mtodo s aplicvel
n folha mais distante da raiz da rvore. Sendo assim, o nmero a chaves inteiras positivas, no duplicadas e menores do que M,
de comparaes realizadas por estes mtodos proporcional a h, onde M o tamanho da tabela de endereamento.
onde h representa a altura da rvore. Uma tabela hash pode ser descrita como uma estrutura de dados
eficaz para implementao de um dicionrio. Embora a busca por
Listagem 10. Implementao do mtodo de insero em uma ABB.
um elemento em uma tabela de espalhamento possa demorar tanto
quanto em uma lista encadeada o nmero de comparaes no
private Noh inserirRecursivo(Item it, Noh raiz) throws Exception { pior caso proporcional a n na prtica, hashing funciona bem.
if (raiz == null) return new Noh(it, null, null);
else if (raiz.item.compara(it) == Item.MENOR) Em geral, o nmero de comparaes mdio para pesquisar um
raiz.dir = inserirRecursivo(it, raiz.dir); elemento em uma tabela de espalhamento constante. Esse um
else raiz.esq = inserirRecursivo(it, raiz.esq); tipo de estrutura interessante para aplicaes (por exemplo, um
return raiz;
} compilador precisa realizar inmeras consultas em sua tabela de
smbolos durante a compilao de um programa) em que a busca
@Override
em um conjunto de dados realizada tantas vezes que um nmero
public void inserir(Item it) throws Exception {
this.raiz = inserirRecursivo(it, this.raiz); de comparaes proporcional a lgn ainda alto.
} Um mtodo de pesquisa que utiliza hashing constitudo de
duas etapas principais:
1. Computar o valor da funo de transformao ou funo
Para uma rvore perfeitamente balanceada, isto , uma rvore hashing: responsvel por transformar a chave de pesquisa em
cujos ns internos tm dois filhos e todas as folhas esto no mesmo um endereo da tabela hash;
nvel, possvel provar que h = lgn, portanto, pesquisa e insero 2. Tratar as colises: considerando que duas ou mais chaves
podem ser realizadas com C(n) = lgn comparaes. podem ser transformadas em um mesmo endereo, necessrio
Um ponto importante a ser destacado que, ao contrrio do realizar o tratamento de colises.
que acontece na implementao do dicionrio com vetores, tanto
o tempo de busca quanto o tempo de insero de um elemento Funo de transformao
no conjunto, utilizando ABB, proporcional a lgn. No caso do Uma funo de transformao responsvel por mapear chaves
dicionrio com vetores, o tempo de insero de um elemento em inteiros dentro do intervalo [0.. M 1], onde M o tamanho
proporcional a n, ou seja, bem maior do que lgn. da tabela na qual os dados estaro armazenados. A funo de
Contudo, importante ressaltar que as ABBs sofrem de um transformao ideal aquela que: (i) simples de ser computada;
problema que pode prejudicar seu tempo de execuo. Quando e (ii) para cada chave de entrada, qualquer valor entre [0..M-1]
os elementos de uma ABB so inseridos em ordem, crescente ou igualmente provvel de ocorrer.
decrescente, devido sua propriedade, os elementos formaro Vrias funes de transformao tm sido estudadas por pesqui-
uma grande lista encadeada, o que far com que a altura da rvore sadores ao longo dos anos. Uma destas funes, que bem simples
seja igual a n 1, onde n refere-se quantidade de elementos e que funciona muito bem, a que utiliza o resto da diviso por M:
inseridos na rvore. Alm disso, fcil prever que, aps vrias h(K) = K mod M, onde h(K) a chave transformada e K um inteiro
operaes de insero/remoo, uma ABB tende a ficar desbalan- correspondente chave de pesquisa. Nesta opo, o valor de M
ceada, j que essas operaes no garantem o balanceamento. Para deve ser escolhido com bastante cautela. Vejamos um exemplo
tratar desse problema, h estruturas mais sofisticadas, conhecidas para entender por qu: se M for par, ento h(K) ser par quando K
como rvores balanceadas. Alguns exemplos de rvores balance- for par e ser mpar quando K for mpar, uma vez que o resto da
adas so AVL, rvore Rubro-Negra, entre outras. diviso de um nmero par pelo outro par e o resto da diviso
de um nmero mpar pelo outro mpar. Isso leva a funo de
Pesquisa por Tabela Hash transformao a no espalhar as chaves de forma uniforme. Por
Os mtodos de pesquisa apresentados anteriormente so ba- exemplo, se 90% das chaves forem pares, esses 90% iro ocupar
seados na comparao da chave de pesquisa com as chaves do 50% da tabela de endereamento e os outros 10% ocuparo os
conjunto de dados. O mtodo de pesquisa por tabela hash (ou 50% restantes.
hashing) completamente diferente: os registros armazenados em O ideal que M seja um nmero primo, mas no qualquer primo.
uma tabela so diretamente endereados a partir de uma trans- Segundo Cormen et al. (2012), o ideal escolher um primo no
formao aritmtica realizada sobre a chave de pesquisa. muito prximo de uma potncia de 2. Por exemplo, se desejamos
O hashing uma extenso do mtodo de pesquisa indexado por criar uma tabela de espalhamento para conter aproximadamente
chave (key-indexed search method) que usa valores das chaves como 2000 chaves e no nos importamos de examinar, por exemplo, uma
ndices de um vetor, em vez de compar-las. A grande vantagem mdia de trs elementos em uma busca malsucedida, podemos
deste mtodo que inseres, remoes e consultas a elementos do escolher uma tabela de espalhamento de tamanho M = 701, uma
conjunto podem ser realizadas com um nmero de comparaes vez que 701 um primo prximo de 2000/3 e no muito prximo
(1 * 52) + (1 * 51) + 2 = 32
(2 * 52) + (1 * 51) + 1 = 56
@Override
public Item pesquisar(Item it) throws Exception {
return pesquisarLista(it, table[hash(it, M)]);
}
@Override
public void inserir(Item it) throws Exception {
int i = hash(it, M);
table[i] = new Noh(it, table[i]);
}
Vantagens e desvantagens
dos padres de projeto
Singleton e Flyweight
Conhea neste artigo as vantagens, desvantagens,
quando e como utilizar os padres de projeto
Singleton e Flyweight
@javax.ejb.Singleton, demonstrada na Listagem 5. Sua principal Vejamos um exemplo desta situao. Suponha que sua aplicao
diferena em relao ao Stateful SessionBean que existir uma no executada em um ambiente distribudo e seu Singleton
nica instncia do objeto por JVM. SessionBean tenha sido modelado com o intuito de compartilhar
o estado. No entanto, algum tempo depois, voc decide tornar a
Listagem 3. Singleton protegido do retorno de uma nova instncia na desserializao. sua aplicao distribuda, acarretando em novas instncias do
Singleton de acordo com os ns do cluster (j que existir uma
import java.io.ObjectStreamException;
import java.io.Serializable;
instncia por JVM). Diante disso, como podemos compartilhar
esse estado desses objetos entre as diversas instncias geradas?
public final class SuaClasseSingleton implements Serializable { Para solucionar esse problema, uma tcnica que pode ser adotada
private static final long serialVersionUID = 1L;
compartilhar o estado do Singleton atravs de um sistema de
private static final SuaClasseSingleton INSTANCE = new SuaClasseSingleton(); cache de segundo nvel com suporte a replicao de dados
entre os ns do ambiente clusterizado como, por exemplo, o
private SuaClasseSingleton() {}
Infinispan.
public static SuaClasseSingleton getInstance() { Alm da facilidade de criao de um Singleton SessionBean, a
return INSTANCE;
especificao Enterprise JavaBeans 3.1 oferece outros benefcios,
}
a saber:
public void qualquerMetodoDeNegocio() {} Uso da anotao @Startup para inicializar o Singleton junto ao
carregamento da aplicao;
/*
* Mtodo que ser invocado pelo Java no processo de desserializao. Uso da anotao @DependsOn para definir a ordem de inicia-
* Garantimos a unicidade retornando o objeto referenciado pelo lizao entre diversos Singletons;
* atributo esttico INSTANCE.
*/
Uso da anotao @ConcurrencyManagement para especificar
private Object readResolve() throws ObjectStreamException { quem controlar o acesso concorrente ao objeto, se o prprio bean
return INSTANCE; ou o container.
}
}
Essas anotaes so parte da Java Enterprise Edition 6. Nessa
Listagem 4. Estrutura simples e pouco conhecida de um Singleton. plataforma, alm do EJB 3.1, temos tambm o CDI (Context and
public enum SuaClasseSingletonEnum { Dependency Injection, especificado pela JSR-299), que define um
comportamento diferente para a anotao @Singleton. Ao uti-
INSTANCE;
lizarmos EJBs, somos beneficiados pelo controle transacional,
public void qualquerMetodoDeNegocio() {} concorrncia no acesso ao objeto e distribuio do Singleton Ses-
} sion Bean. Porm, quando precisamos criar um objeto nico mais
Listagem 5. Exemplo de Singleton SessionBean.
simplificado, utilizamos o CDI, pois dessa forma o servidor de
aplicao fica responsvel apenas por gerenciar o ciclo de vida do
import javax.ejb.Singleton; Singleton, no havendo preocupao com transaes, concorrncia
@Singleton de acesso ou distribuio do objeto criado.
public class SeuEJBSingleton {
}
public void qualquerMetodoDeNegocio() {} Introduo ao Flyweight
Assim como o Singleton, o padro Flyweight que em Portugus
significa peso-mosca, a categoria mais leve do boxe tambm
Ao traar um paralelo com a implementao do Singleton, faz parte do catlogo de Design Patterns do GoF, pertencendo
por sua vez, comum pensarmos que existir apenas uma categoria de padres Estruturais. O Flyweight utilizado para
instncia do Singleton SessionBean por aplicao, mesmo em compartilhar objetos otimizando o uso da memria e o desempe-
um ambiente distribudo em vrios ns. Porm, a especificao nho em relao ao tempo de execuo do seu cdigo. Seu objetivo
estabelece que caso sua aplicao esteja em execuo em um estabelecer um padro para cachear objetos muito utilizados
ambiente clusterizado, por exemplo, com dez ns, existiro na aplicao e facilitar a manipulao de grandes quantidades
dez instncias diferentes do Singleton SessionBean, uma em de dados.
cada JVM. Dessa forma, se seu Singleton foi projetado como Conceitualmente, o uso eficiente do Flyweight ocorre quando
um servio que mantm o estado de objetos em memria, se- possumos muitas instncias de uma classe e quando parte
ro dez instncias do mesmo, uma para cada n (JVM). Nesse destas instncias podem ser substitudas por poucos objetos
momento ento, temos um problema, pois cada n mantm as compartilhados.
informaes de forma independente, gerando divergncias Para entendermos melhor o funcionamento do Flyweight, vamos
que podem comprometer o funcionamento e a consistncia trazer esse conceito para um problema real: considere que precisa-
da aplicao. mos modelar a construo de uma loja que vende exclusivamente
Listagem 6. Cdigo da interface Computer. Listagem 8. Cdigo das classes ApplicationServer e DataBaseServer.
Listagem 12. Inner class IntegerCache da classe java.lang.Integer. Quanto ao Flyweight, vale ressaltar sua eficincia em situaes
simples, que sugerem evitar repeties na criao de objetos e
/*
* Classe interna privada e esttica da classe java.lang.Integer. Extrados trechos de
assim prover a reutilizao de instncias. Sempre que estiver
* cdigo que representam o uso de Flyweight para reutilizao de valores numricos em dvida sobre quando aplicar esse pattern, lembre-se que se
* entre -128 e 127. sua soluo possui um grande nmero de objetos imutveis que
*/
private static class IntegerCache { podem ser reutilizados, o uso do Flyweight deve ser considerado,
static final int low = -128; melhorando o desempenho e proporcionando uma economia
static final int high = 127;
de memria.
// +1 para considerar o valor zero entre -128 e 127.
static final Integer[] cache = new Integer[(high - low) + 1];
static {
int j = low;
for (int k = 0; k < cache.length; k++) { Autor
vcache[k] = new Integer(j++);
} Ednardo Luiz Martins
} ednardomartins@gmail.com
} Graduado em Cincias da Computao pela Universidade
Federal de Ouro Preto. Em contato com Java desde 2002,
trabalhou como Arquiteto Java em alguns projetos na rea de Segu-
Quando nos deparamos com essa situao, uma soluo im- rana Pblica e Justia. Atualmente Analista de Sistemas Snior em
plementar o padro Service Locator do Core J2EE Patterns. Dessa Florianpolis/SC.
forma, sempre que precisarmos de um EJB fora do servidor de
aplicao, podemos solicitar ao nosso Service Locator. No entanto,
mesmo com a criao desse servio, a operao de localizao ma- Autor
nual pode ter um alto custo, porque envolve o acesso ao servidor Ricardo da S. Longa
de nomes do servidor de aplicao e a obteno do objeto remoto ricardo.longa@gmail.com
Proxy. Dependendo do nmero de objetos e do nmero de vezes Graduado em Sistemas de Informao e ps-graduado em
que esta operao for executada, podemos onerar a performance Engenharia de Software pela Universidade do Sul de Santa
da aplicao. Catarina, um arteso de software h 11 anos, blogueiro nas horas vagas
Com o objetivo de melhorar o servio de localizao de um proxy, e professor de cursos tcnicos, graduao e ps-graduao. Atualmente
trabalha como Analista de Sistemas na Neoway Business Solutions, realiza palestras
implementamos o Flyweight para armazenar e compartilhar esse
relacionadas ao Java/Android desde 2013 e integrante/evangelista do Grupo de
objeto. Dessa forma, a localizao realizada apenas uma vez e
Usurios Java de SC.
reaproveitada todas as vezes que precisarmos utiliz-lo.
O entendimento dos padres de projeto em sua plenitude es-
sencial para a eficincia da implementao quando for necessrio Links:
utiliz-los. Sabendo disso, nosso principal objetivo despertar
no leitor uma viso crtica sobre dois importantes padres: o What is CDI?
Flyweight e o Singleton. http://cdi-spec.org/
Neste contexto, diversas peculiaridades sobre o Singleton ainda Pgina da especificao do EJB 3.1.
so obscuras a muitos desenvolvedores da plataforma Java EE, https://jcp.org/en/jsr/detail?id=318
principalmente quando se trata de projetos que so executados
sobre um servidor em cluster. Peculiaridades estas que podem GAMMA, Erich; HELM, Richard; JOHNSON, Ralph; VLISSIDES, John. DESIGN
PATTERNS: Elements of reusable object-oriented software. Addison-Wesley
causar uma srie de transtornos, tais como a criao de novas
Longman, Inc. 1995.
instncias via desserializao, a no replicao automtica do
estado de cada instncia de EJB Singleton rodando em cada n KERIEVSKY, Joshua. REFACTORING TO PATTERNS. Person Education, Inc. 2005.
do cluster (quando espera-se um nico Singleton com estado
ALUR, Deepak; CRUPI, John; MALKS, Dan. CORE J2EE PATTERNS: Best Practices and
para a aplicao) e as diferenas em relao ao EJB Singleton e o Design Strategies. Prentice Hall / Sun Microsystems Press. 2003.
Singleton do CDI.
10. Feito isso, a prxima tela permite ao usurio configurar o uma aplicao desktop. O objetivo desta ser gerenciar o cadastro
MySQL como um servio do Sistema Operacional Windows. Para de projetos de uma empresa.
tanto, basta manter os valores default e clicar em Next; O sistema que construiremos conter apenas trs entidades (Fun-
11. A janela que aparecer detalha todos os passos de configura- cionario, Projeto e Trabalha) e a partir delas sero construdas as
o que sero aplicados. Confirmadas estas escolhas, clique em principais operaes realizadas sobre um cadastro, como salvar,
Execute, como pode ser visto na Figura 4; atualizar, listar e excluir.
12. Neste momento, uma tela mostrando o fim do processo ser As informaes que cada funcionrio carregar so: cdigo,
exibida. Clique ento em Finish; nome, CPF, cargo, endereo e salrio. J um projeto conter: um
13. Ento, uma nova janela informa que a configurao do MySQL cdigo, nome, data de incio e data de trmino.
Server foi realizada (Figura 5). Clique pela ltima vez em Next; A entidade Trabalha resultado da relao muitos para muitos
14. Para encerrar, uma janela exibida indicando que a instalao existente entre Funcionario e Projeto e armazenar o cdigo de
foi concluda. Neste momento, apenas clique em Finish. ambos. Saiba que no necessrio criar uma classe mapeada para
essa entidade, uma vez que o prprio Hibernate gera uma tabela
Desenvolvendo o cadastro de funcionrios de ligaopara viabilizar esse relacionamento.
Agora que temos o banco de dados instalado, assim como o A Figura 6 mostra o relacionamento existente (diagrama entida-
Eclipse e o Maven integrados, vamos partir para a construo de de relacionamento) entre as tabelas do banco de dados.
Listagem 2. Configurao do arquivo pom.xml. Ainda podemos utilizar as anotaes @Column e @Table, que
so usadas para personalizar o nome das tabelas e das colunas,
01. <project xmlns=http://maven.apache.org/POM/4.0.0 bastando informar o nome entre parnteses. No nosso caso, como
xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance
no adicionamos essa informao, fica considerado que o nome
xsi:schemaLocation=http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd>
das tabelas e colunas ser exatamente igual ao nome das classes
02. <modelVersion>4.0.0</modelVersion> e suas propriedades.
03. <groupId>br.com.devmedia</groupId> A anotao que indica que a entidade criada passar por audi-
04. <artifactId>hibernate-envers-01</artifactId> toria pode ser vista na linha 6. Trata-se da anotao @Audited,
05. <version>0.0.1-SNAPSHOT</version>
pertencente ao pacote org.hibernate.envers. A presena dela faz
06. <dependencies>
07. <dependency>
com que outra tabela seja criada no banco, sendo utilizada para
08. <groupId>mysql</groupId> armazenar todas as alteraes sofridas pela entidade auditada.
09. <artifactId>mysql-connector-java</artifactId> O nome da tabela criada automaticamente pode ser customizado
10. <version>5.1.34</version> atravs da anotao @AuditTable. Quando no se utiliza essa ano-
11. </dependency> tao, o Envers entende que a nomenclatura da tabela de histrico
12. <dependency>
deve ter o nome da classe com o sufixo _AUD.
13. <groupId>org.hibernate</groupId>
14. <artifactId>hibernate-core</artifactId> Agora vamos criar a outra classe, que mapear a entidade Pro-
15. <version>4.3.8.Final</version> jeto. Os passos so idnticos aos executados para criar a classe
16. </dependency> Funcionario. Na Listagem 4 possvel visualizar seu cdigo.
17. <dependency> Assim como na classe Funcionario, perceba na linha 6 a presen-
18. <groupId>org.hibernate</groupId>
a da anotao @Audited, indicando que a entidade em questo
19. <artifactId>hibernate-envers</artifactId>
20. <version>4.3.8.Final</version>
sofrer auditoria. Portanto, uma tabela de histrico de nome pro-
21. </dependency> jeto_AUD ser criada no banco de dados para armazenar todas
22. </dependencies> as alteraes ocorridas nessa entidade.
23. </project>
atributos no sero modificados. Este estado interno inclui o me- jm.acessobd clicando com o boto direito do mouse sobre o projeto
tadata referente ao mapeamento objeto relacional das entidades do hibernate-envers-01, escolhendo New > Package e informando com.
sistema e tambm a referncia de quem ir fornecer as conexes jm.acessobd como nome.
com o banco de dados. Por esse motivo, a classe HibernateUtil Criado o pacote, clique sobre ele com o boto direito, escolha
utiliza-se do mtodo esttico getSessionFactory(), visto na linha 9, New > Class e d o nome classe de FuncionarioDAO.
para oferecer sempre a mesma instncia de um SessionFactory O cdigo fonte dessa classe deve ficar semelhante ao apresentado
no contexto da aplicao. na Listagem 7.
Por fim, na linha 15, temos o mtodo privado esttico build- Na linha 9, dentro do construtor da classe FuncionarioDAO,
SessionFactory(), que responsvel por construir a instncia de o mtodo getSessionFactory() invocado para a criao de um
SessionFactory. Essa construo feita com base no arquivo de SessionFactory. Esse objeto deve ser criado uma nica vez, pois,
configurao do Hibernate. por armazenar os mapeamentos e configuraes do Hibernate,
muito pesado e lento de se criar.
Persistindo dados no banco J na linha 12, o mtodo adicionarFuncionario() recebe como
Agora, criaremos as classes que sero responsveis por via- parmetro os dados do funcionrio e realiza a insero deste no
bilizar todas as operaes de persistncia disponibilizadas banco de dados. Para isso, na linha 13 obtida uma sesso a partir
pela aplicao. Para isso, criemos primeiramente o pacote com. de um SessionFactory.
Listagem 7. Cdigo da classe FuncionarioDAO. Disponibiliza todas as operaes que sero realizadas no banco de dados.
Listagem 8. Cdigo da classe ProjetoDAO. Disponibiliza todas as operaes que sero realizadas no banco de dados.
da classe Funcionario. Esses objetos so internalizados no banco J a tabela REVINFO inclui os seguintes campos: REV, que faz a
de dados atravs do mtodo adicionarFuncionario(), implemen- ligao com as tabelas de auditoria individuais (as de final _aud);
tado na classe FuncionarioDAO. e REVTSTMP, que indica o momento exato (timestamp) em que a
A Listagem 10 mostra o resultado da execuo dessa classe, operao ocorreu.
obtido atravs do console da IDE Eclipse. A Figura 8 mostra as alteraes provocadas na estrutura do
banco de dados aps a execuo da classe de teste. Note que alm
Listagem 9. Cdigo da classe de teste 1. das tabelas mencionadas, foram criadas as tabelas versionadas
Projeto_AUD e Trabalha_AUD, que armazenaro o histrico das
01. package com.jm.teste;
02. //imports omitidos...
mudanas sofridas por suas respectivas entidades. Nesse momen-
03. to, essas tabelas encontram-se vazias pois ainda no foi realizada
04. public class TesteEnvers1 { qualquer operao sobre as tabelas originais.
05.
06. public static void main(String[] args) throws ParseException {
07.
08. Funcionario funcionario1 = new Funcionario(Clenio Rocha,
Analista de TI, 5600, 06493084765, Rua Rio Paranaiba);
09. Funcionario funcionario2 = new Funcionario(Carlos Martins,
Analista de TI, 4300, 06433055765, Rua Abadia dos Dourados);
10. Funcionario funcionario3 = new Funcionario(Daniel Cioqueta,
Analista de TI, 4200, 06493084444, Rua Rio das Ostras);
11. Funcionario funcionario4 = new Funcionario(Yujo Rodrigues,
Gerente de Projetos, 4110, 07777775765, Rua dos Patos);
12.
13. FuncionarioDAO funcionarioDao = new FuncionarioDAO();
14. funcionarioDao.adicionarFuncionario(funcionario1);
15. funcionarioDao.adicionarFuncionario(funcionario2);
16. funcionarioDao.adicionarFuncionario(funcionario3);
17. funcionarioDao.adicionarFuncionario(funcionario4);
Figura 8. Viso do banco de dados aps a execuo da classe de teste
18. }
19. }
Listagem 10. Sada gerada pela execuo da classe TesteEnvers1. A Figura 9 mostra os registros adicionados tabela Funcio-
nario_ AUD. Alm de todos os campos auditados, podemos
01. Hibernate: insert into Funcionario (cargo, cpf, endereco, nome, salario) verificar as colunas REV e REVTYPE. A primeira coluna, como
values (?, ?, ?, ?, ?)
02. Hibernate: insert into REVINFO (REVTSTMP) values (?) j mencionado, armazena o identificador da reviso, e chave
03. Hibernate: insert into Funcionario_AUD (REVTYPE, cargo, cpf, endereco, estrangeira da tabela REVINFO. J a segunda coluna indica
nome, salario, codigo, REV) values (?, ?, ?, ?, ?, ?, ?, ?)
o tipo de ao executada. O valor 0 indica que foi adicionado
04. Hibernate: insert into Funcionario (cargo, cpf, endereco, nome, salario)
values (?, ?, ?, ?, ?) um novo registro. A Figura 9 mostra, ainda, a partir de uma
05. Hibernate: insert into REVINFO (REVTSTMP) values (?) consulta, como ficou a tabela REVINFO. Essa tabela armazena
06. Hibernate: insert into Funcionario_AUD (REVTYPE, cargo, cpf, endereco,
os identificadores das revises, assim como o momento em que
nome, salario, codigo, REV) values (?, ?, ?, ?, ?, ?, ?, ?)
07. Hibernate: insert into Funcionario (cargo, cpf, endereco, nome, salario) cada operao ocorreu.
values (?, ?, ?, ?, ?) Dando sequncia aos testes, vamos realizar mais algumas aes
08. Hibernate: insert into REVINFO (REVTSTMP) values (?)
09. Hibernate: insert into Funcionario_AUD (REVTYPE, cargo, cpf, endereco,
contra o banco de dados para avaliar outros detalhes sobre como
nome, salario, codigo, REV) values (?, ?, ?, ?, ?, ?, ?, ?) o Hibernate Envers se comporta. Para isso, execute o cdigo da
10. Hibernate: insert into Funcionario (cargo, cpf, endereco, nome, salario) classe TesteEnvers2, apresentado na Listagem 11.
values (?, ?, ?, ?, ?)
11. Hibernate: insert into REVINFO (REVTSTMP) values (?)
O objetivo desta classe cadastrar um projeto e associar al-
12. Hibernate: insert into Funcionario_AUD (REVTYPE, cargo, cpf, endereco, guns funcionrios a ele. Os funcionrios associados ao projeto
nome, salario, codigo, REV) values (?, ?, ?, ?, ?, ?, ?, ?) sero aqueles criados na execuo anterior e que nesse momento
encontram-se na base de dados. A Listagem 12 mostra o resultado
Perceba que, alm dos inserts na tabela funcionario (linhas 1, 4, da execuo, obtido atravs do console do Eclipse.
7 e 10), foram feitas inseres em outras duas tabelas: REVINFO Analisando o resultado da execuo da classe TesteEnvers2, note
e Funcionario_AUD. que realizada uma busca por todos os funcionrios cadastrados
A tabela Funcionario_ AUD armazenar o histrico de mu- na linha 1. Como trata-se de uma busca e nenhuma alterao
danas sofridas pela entidade funcionrio, sendo composta por realizada nas tabelas auditadas, nenhum insert ser registrado
todos os campos auditados da tabela original, alm de outros nas tabelas versionadas.
dois atributos: o cdigo da reviso (REV), que representa a Na linha 2, nota-se que foi criada uma entrada na tabela projeto.
chave primria da tabela; e o tipo de reviso (REVTYPE), que Esta ao gerou na linha 12 a adio de um registro na tabela
representa a ao executada, como incluso, alterao ou ex- Projeto_AUD. Esse registro contm os campos da tabela original,
cluso de dados. o tipo de operao e o cdigo da reviso.
Autor
Carlos Alberto Silva
casilvamg@hotmail.com
formado em Cincia da Computao pela Universidade Federal
de Uberlndia (UFU), com especializao em Desenvolvimento
Java pelo Centro Universitrio do Tringulo (UNITRI) e em Anlise e De-
senvolvimento de Sistemas Aplicados a Gesto Empresarial pelo Instituto
Federal do Tringulo Mineiro (IFTM). Trabalha atualmente na empresa Algar Telecom como
Analista de TI. Possui as seguintes certificaes: OCJP, OCWCD e ITIL.
Links:
Figura 10. Viso das tabelas aps a execuo da classe TesteEnvers2
Site oficial do Hibernate Envers.
Por fim, a tabela REVINFO (vide linha 11) recebeu a incluso http://hibernate.org/orm/envers/
de um registro que contm o identificador da nova reviso e o Site oficial do MySQL.
momento exato em que ela ocorreu. http://www.mysql.com/
A Figura 10 mostra a viso das tabelas do banco aps a execuo
Endereo para download do driver do MySQL.
da classe TesteEnvers2.
http://dev.mysql.com/downloads/connector/j/
O Hibernate Envers um poderosssimo recurso para realizao
de auditoria que torna desnecessrio, por exemplo, criar uma Site oficial do Eclipse.
estrutura especfica para as auditorias diretamente no SGBD, https://eclipse.org/downloads/
como Stored Procedures ou triggers, recursos muito utilizados Endereo para download do JDK.
nos sistemas atuais. http://www.oracle.com/technetwork/java/javase/downloads
Diante disso, no desenvolvimento de projetos que requerem
auditoria, certamente o desenvolvedor poder incorporar o Envers Endereo para download do Maven.
http://maven.apache.org/download.html
para o tratamento deste requisito, minimizando os impactos por
ser um framework transparente, baseado em revises e, principal- Christian Bauer, Gavin King. Livro Java Persistence com Hibernate, 2005.
mente, por no ser intrusivo.