hibernate 3

Upload: dann-volpato

Post on 12-Oct-2015

3 views

Category:

Documents


0 download

TRANSCRIPT

  • Comunidade Livre Parabahttp://www.softwarelivre.pb.gov.br/

    Introduo ao Hibernate 3

    Maurcio Linhares

    Mapeie o seu modelo de objetos diretamente para o banco de dados, de uma forma simples ese livrando de vez da SQL

    O que o Hibernate?

    O Hibernate uma ferramenta de mapeamento objeto/relacional para Java. Ela transforma os dadostabulares de um banco de dados em um grafo de objetos definido pelo desenvolvedor. Usando oHibernate, o desenvolvedor se livra de escrever muito do cdigo de acesso a banco de dados e de SQLque ele escreveria no usando a ferramenta, acelerando a velocidade do seu desenvolvimento de umaforma fantstica.

    Mas o framework no uma boa opo para todos os tipos de aplicao. Sistemas que fazem usoextensivo de stored procedures, triggers ou que implementam a maior parte da lgica da aplicao nobanco de dados, contando com um modelo de objetos pobre no vai se beneficiar com o uso doHibernate. Ele mais indicado para sistemas que contam com um modelo rico, onde a maior parte dalgica de negcios fica na prpria aplicao Java, dependendo pouco de funes especficas do banco dedados.

    Antes de voc seguir em frente...Antes de comear voc deve fazer o download de uma verso estvel do Hibernate 3, depreferncia a verso 3.0.5, com a qual este artigo foi testado. Voc pode encontrar osarquivos dela aqui:

    https://sourceforge.net/project/showfiles.php?group_id=40712&package_id=127784

    Depois de fazer o download, adicione o arquivo hibernate3.jar e os seguintes arquivosda pasta lib do download ao seu classpath (ou ao classpath da sua IDE):

    ehcache-1.1.jarjta.jarxml-apis.jarcommons-logging-1.0.4.jarc3p0-0.8.5.2.jarasm-attrs.jarlog4j-1.2.9.jardom4j-1.6.jarantlr-2.7.5H3.jarcglib-2.1.jarasm.jarjdbc2_0-stdext.jarxerces-2.6.2.jarcommons-collections-2.1.1.jar

    O banco de dados escolhido para este artigo o MySQL, verso 4.1, mas os scripts SQLpra gerar as tabelas podem ser facilmente adaptados para outros bancos. Usando oMySQL voc tambm vai ter que colocar o driver JDBC dele no seu classpath, ele podeser baixado no seguinte endereo (a verso utilizada no artigo foi a 3.1.8):

    http://dev.mysql.com/downloads/connector/j/3.1.html

    Alm do driver do MySQL, voc tambm vai ter que adicionar os arquivos .JAR queesto na pasta lib do arquivo do driver, o aspectjrt.jar e o aspectjtools.jar.

    Grupo de Usurios Java http://www.guj.com.br Pgina 1

  • Comunidade Livre Parabahttp://www.softwarelivre.pb.gov.br/

    Voc tambm deve criar o banco de dados, usando o arquivo banco.sql que est juntocom os outros anexos desse artigo.

    Neste artigo voc vai conhecer um pouco sobre os mapeamentos do Hibernate e a HQL, a linguagemde buscas do framework. O artigo assume que voc j tenha um conhecimento sobre a linguagem Java,bancos de dados e XML, alm de ser capaz de montar um ambiente de desenvolvimento Java com todasas configuraes necessrias.

    Definindo os objetos do modelo e as tabelas do banco

    O nosso modelo simples, ele modela um cadastro de alunos em uma universidade. Nele ns temos asclasses, Pessoa, Aluno, Professor, Endereo, Turma, Disciplina e Curso, que se relacionam comomostrado no seguinte diagrama:

    A classe Pessoa, que tem um Endereo, a classe base para as classes Aluno e Professor. UmAluno pode estar em vrias Turmas, assim como um Professor. Cada Turma pode ter vrios Alunos eapenas um Professor. A Turma tem ainda uma Disciplina, que pode conter vrias Turmas e que temum Curso, que tambm pode ter vrias Disciplinas.

    Com um modelo de objetos criado, vejamos como essas classes poderiam ser transformadas emtabelas, neste diagrama:

    Grupo de Usurios Java http://www.guj.com.br Pgina 2

  • Comunidade Livre Parabahttp://www.softwarelivre.pb.gov.br/

    Como voc j deve ter percebido, no h nada demais com esse modelo de banco de dados, astabelas esto interligadas normalmente usando chaves primrias e chaves estrangeiras e uma tabela derelacionamento, no caso da relao N:N entre Aluno e Turma ( use o script para criar as tabelas que estnos materiais anexos ao artigo). As tabelas tem as mesmas propriedades das classes e os mesmosrelacionamentos.

    Dando nome aos boisQuando estiver mapeando as suas classes do modelo para o banco de dados, tenteusar os mesmos nomes das classes e de suas propriedades, isso vai evitar vrias doresde cabea, como no saber se o nome daquela propriedade todo em maisculas,ou se tem um _ (underline) entre um nome e outro. Alm do que, se os nomesforem iguais, voc no precisa repetir os nomes das tabelas e dos relacionamentos nomapeamento do Hibernate.

    Agora que j temos as nossas classes e elas foram mapeadas para o banco, podemos comear atrabalhar com os mapeamentos do Hibernate, pra fazer com que aquelas tabelas do banco setransformem nas nossas classes do modelo, quando fizermos acesso ao banco de dados.

    Mapeando as classes para as tabelas

    Antes de comear a fazer os mapeamentos do Hibernate, temos um conceito do banco de dados queprecisa ser revisto, a identidade. Para um banco de dados, o modo de diferenciar uma linha das outras, usando chaves, de preferncia chaves no naturais, como as colunas id que ns criamos para nossastabelas, mas no nosso modelo orientado a objetos, a identidade no encontrada dessa forma. Em Java,ns definimos a identidade dos objetos sobrescrevendo o mtodo Object.equals(Object object), domodo que nos convier. A implementao default deste mtodo, define a identidade atravs da posiode memria ocupada pelo objeto.

    No podemos usar o mtodo equals() no banco de dados, porque o banco de dados no sabe quetemos objetos, ele s entende tabelas, chaves primrias e estrangeiras. A soluo adicionar aos nossosobjetos um identificador no natural, como os que ns encontramos no banco de dados, porque assim obanco de dados e o prprio Hibernate vo ser capazes de diferenciar os objetos e montar os seusrelacionamentos. Ns fazemos isso adicionando uma propriedade chamada id do tipo Integer a todas asnossas classes, como no exemplo de cdigo a seguir:

    Grupo de Usurios Java http://www.guj.com.br Pgina 3

  • Comunidade Livre Parabahttp://www.softwarelivre.pb.gov.br/

    //Listagem do arquivo Pessoa.java

    public class Pessoa {

    private String nome; private String email; private String telefone; private Endereco endereco;

    private Integer id;

    //mtodos getters e setters das propriedades

    }

    Poderamos ter escolhido o tipo primitivo int para a propriedade, mas trabalhando com objetos, omapeamento e a resoluo se um objeto existe ou no no banco de dados torna-se mais simples para oHibernate. Outra observao importante so os mtodos getters e setters para as propriedades dosobjetos. O Hibernate no precisa de que as propriedades sejam definidas usando a nomenclatura dosJavaBeans, mas isso j uma boa prtica comum na comunidade, alm de existirem outros frameworkse tecnologias que exigem essa nomenclatura (como a Expression Language dos JSPs), ento nsdefinimos mtodos getters e setters para todas as propriedades nos nossos objetos.

    Conhecendo o arquivo hmb.xml e mapeando um relacionamento 1:1

    Cortemos a conversa fiada e vamos iniciar a construo dos mapeamentos. O primeiro mapeamentoabordado o da classe Pessoa e do seu relacionamento com a classe Endereo. No nosso modelo, umEndereo tem apenas uma Pessoa e uma Pessoa tem apenas um Endereo (perceba que o arquivo .javae o nome da classe Java que modela Endereo no tem o , ficou Endereco, para ficar com o mesmonome da tabela). Vejamos o mapeamento para a classe Pessoa (o arquivo Pessoa.hbm.xml):

    Nomes de arquivos e extenses uma boa prtica usar um arquivo de mapeamento para cada classe e usar comoextenso do arquivo .hbm.xml para diferenciar de outros arquivos XML utilizadosna aplicao.

    Grupo de Usurios Java http://www.guj.com.br Pgina 4

  • Comunidade Livre Parabahttp://www.softwarelivre.pb.gov.br/

    O arquivo de mapeamento um arquivo XML que define as propriedades e os relacionamentos de umaclasse para o Hibernate, este arquivo pode conter classes, classes componentes e queries em HQL ou emSQL. No nosso exemplo, temos apenas uma classe sendo mapeada no arquivo, a classe Pessoa. Oarquivo XML comea normalmente com as definies da DTD e do n raiz, o , depoisvem o n que nos interessa neste caso, .

    No n ns definimos a classe que est sendo mapeada e para qual tabela ela vai ser mapeada.O nico atributo obrigatrio deste n name, que deve conter o nome completo da classe (com opacote, se ele no tiver sido definido no atributo package do n ), se o nome daclasse for diferente do nome da tabela, voc pode colocar o nome da tabela no atributo table, no nossoexemplo isso no necessrio.

    Seguindo em frente no nosso exemplo, temos o n que o identificador dessa classe no banco dedados. Neste n ns definimos a propriedade que guarda o identificador do objeto no atributo name, queno nosso caso id, se o nome da coluna no banco de dados fosse diferente da propriedade do objeto,ela poderia ter sido definida no atributo column. Ainda dentro deste n, ns encontramos mais um n, o, este n guarda a informao de como os identificadores (as chaves do banco de dados) sogerados, existem diversas classes de geradores, que so definidas no atributo class do n, no nossocaso o gerador usado o increment, que incrementa um ao valor da chave sempre que insere um novoobjeto no banco, esse gerador costuma funcionar normalmente em todos os bancos.

    Os prximos ns do arquivo so os que indicam propriedades simples dos nossos objetos,como Strings, os tipos primitivos (e seus wrappers), objetos Date, Calendar, Locale, Currency e outros.Neste n os atributos mais importante so name, que define o nome da propriedade, column paraquando a propriedade no tiver o mesmo nome da coluna na tabela e type para definir o tipo do objetoque a propriedade guarda. Normalmente, o prprio Hibernate capaz de descobrir qual o tipo deobjeto que a propriedade guarda, no sendo necessrio escrever isso no arquivo de configurao, eletambm usa o mesmo nome da propriedade para acessar a coluna, se o atributo no tiver sidopreenchido. Ns definimos as trs propriedades simples da nossa classe, nome, email e telefone.

    O ltimo n do arquivo, , define o relacionamento de 1-para-1 que a classe Pessoa temcom a classe Endereo. Este n tem os atributos name, que define o nome da propriedade no objeto(neste caso, endereco), type que define a classe da propriedade e cascade que define como oHibernate deve cascatear as aes feitas nesta classe para a classe relacionada, como atualizaes,inseres e excluses de registro. No nosso caso o cascade foi escolhido como save-update para quequando uma classe pessoa for inserida ou atualizada no banco, a propriedade endereco tambm sejainserida ou atualizada.

    Com isso, terminamos o mapeamento da nossa classe Pessoa, mas este mapeamento faz referncia auma outra classe o Hibernate ainda no conhece, a classe Endereco. Vejamos ento como fica omapeamento desta classe (o arquivo o Endereco.hbm.xml):

    pessoa

    Grupo de Usurios Java http://www.guj.com.br Pgina 5

  • Comunidade Livre Parabahttp://www.softwarelivre.pb.gov.br/

    Como voc agora j conhece a estrutura bsica do arquivo de mapeamento, vejamos as diferenasdeste arquivo para o Pessoa.hbm.xml. A primeira coisa que voc deve estar notando, que o atributoclass do n no increment, foreign e agora tambm temos um corpo do n, com ovalor pessoa. Isso acontece devido ao tipo de relacionamento que ns criamos no banco de dados,entre as tabelas Endereco e Pessoa. Tambm existe mais um n dentro de que no existia nomapeamento anterior, o , esse n serve para passar um parmetro para a classe geradora doidentificador, que neste caso o nome da propriedade dona deste objeto, pessoa.

    Para garantir que cada Endereco pertena a apenas uma Pessoa, fizemos com que a chave primria deEndereco (Pessoa_id) fosse tambm a chave estrangeira que a liga a Pessoa, desse modo, garantimosque cada Endereco pertence a apenas uma Pessoa e vice-versa. Outra novidade que tambm tivemosque colocar o nome da coluna da chave j que ela no igual a o nome da propriedade da classe, apropriedade se chama id e a coluna Pessoa_id, assim, tivemos que declarar o atributo column do n.

    Continuando no mapeamento, encontramos as propriedades simples da classe, que so declaradas demodo idntico as que ns vimos no mapeamento anterior, com o n e com o atributo namecontendo o nome da propriedade. Mais uma vez no indicamos o nome da coluna (porque os nomes soiguais as propriedades) nem o tipo, j que o Hibernate pode descobrir isso sozinho.

    No nosso modelo, o relacionamento entre Pessoa e Endereco bidirecional, o que quer dizer que sempre possvel navegar de um objeto para o outro, pois Pessoa aponta para Endereco e Enderecoaponta para Pessoa. Para simbolizar isso no mapeamento, ns temos que adicionar o n que tambmexiste no mapeamento de Pessoa, . Como voc j percebeu, os atributos continuam osmesmos, name como sendo o nome da propriedade na classe e class como sendo o nome da classedessa propriedade. Mas ns temos um atributo que no existia na relao anterior, constrained, quenessa relao vai significar que existe uma relao entre a chave primria de Endereco e de Pessoa,avisando ao Hibernate que um Endereco no pode existir sem que exista uma Pessoa, assim, mesmo queo banco de dados no garantisse a integridade referencial do sistema, o prprio Hibernate garantiria.

    Mapeando herana

    Continuando o trabalho de mapear o nosso modelo para o Hibernate, vamos para a herana que nsencontramos entre Pessoa, Aluno e Professor. Pessoa a classe pai, da qual Aluno e Professor herdam aspropriedades e comportamentos.

    No Hibernate existem diversas formas de se fazer o mapeamento de uma relao de herana. Usandouma tabela para cada classe filha (a classe pai no teria tabela, as propriedades comuns se repetiriamnas tabelas filhas), usando uma tabela para todas as classes (discriminadores definiriam quando umaclasse ou outra), usando uma tabela para cada uma das classes (uma para a classe pai e mais uma paracada classe filha) ou at mesmo uma mistura de todas essas possibilidades (disponvel apenas na verso3 do Hibernate). Ficou confuso? No se preocupe, neste artigo ns vamos abordar apenas a mais comume mais simples de ser mantida, uma tabela para cada classe.

    No nosso banco de dados, temos uma tabela Pessoa e outras duas tabelas, Aluno e Professor, queesto relacionadas a professor travs de suas chaves primrias a tabela Pessoa, garantindo assim queno existam Alunos ou Professores com o mesmo identificador. Vejamos ento o mapeamento da classeProfessor (o arquivo Professor.hbm.xml):

  • Comunidade Livre Parabahttp://www.softwarelivre.pb.gov.br/

    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

    Nesse mapeamento vemos um n que ns ainda no conhecamos, , que indica omapeamento de herana usando uma tabela para cada classe, porque para retornar o objeto o Hibernateprecisa fazer um join entre as duas tabelas. O atributo name o nome da classe mapeada e o atributoextends recebe o nome da classe pai (neste caso, Pessoa), se o nome da classe no fosse igual ao databela, poderamos adicionar o nome da tabela no atributo table (que foi omitido porque o nome daclasse igual ao nome da tabela).

    Seguindo no mapeamento, percebemos mais um n desconhecido, . Este n avisa ao Hibernate onome da coluna que guarda a chave primria da tabela, que tambm a chave estrangeira que liga atabela Professor a tabela Pessoa. Neste n ns adicionamos o atributo column e colocamos o nome dacoluna que guarda a chave, que Pessoa_id.

    O mapeamento continua com a declarao de uma propriedade e com um n que ns tambm noconhecemos, , que pode simbolizar um relacionamento 1:N ou N:N. Este n vai ser explicado maistarde neste artigo.

    Passando para o mapeamento da classe Aluno, percebemos que no existe muita diferena:

    A classe declarada do mesmo modo que Professor, usando o n e usando osmesmos atributos que foram usados no mapeamento anterior. O n tambm foi includo do mesmomodo, com o nome da coluna da chave primria/estrangeira da tabela, mais uma declarao depropriedade e mais um n , nada alm do que j foi visto.

    Grupo de Usurios Java http://www.guj.com.br Pgina 7

  • Comunidade Livre Parabahttp://www.softwarelivre.pb.gov.br/

    Mapeando associaes 1:N e N:N

    Voc j conheceu o n nos mapeamentos anteriores, vamos entender agora como ele funciona ecomo utiliz-lo para tornar o acesso aos objetos associados ainda mais simples, mais uma vez semnenhuma linha de SQL. Uma set ou conjunto representa uma coleo de objetos no repetidos, quepodem ou no estar ordenados (dependendo da implementao da interface java.util.Set escolhida).Quando voc adiciona um n deste tipo em um arquivo de mapeamento, voc est indicando aoHibernate que o seu objeto tem um relacionamento 1:N ou N:N com outro objeto. Vejamos o exemplo daclasse Professor, que tem um relacionamento 1:N com a classe Turma:

    No n o primeiro atributo a ser encontrado name que assim como nos outros ns, define onome da propriedade que est sendo tratada, j o outro atributo, inverse, define como o Hibernate vaitratar a insero e retirada de objetos nessa associao. Quando um lado da associao define o atributoinverse para true ele est indicando que apenas quando um objeto for inserido do outro lado daassociao ele deve ser persistido no banco de dados.

    Para entender melhor o atributo inverse pense em como est definido o mapeamento da classeProfessor. L ele est definido para true, significando que apenas quando uma Turma adicionar umprofessor, o relacionamento vai ser persistido no banco de dados. Em cdigo:

    Professor professor = new Professor();Turma turma = new Turma();

    turma.setProfessor(professor);professor.getTurmas().add(turma);

    Se apenas o Professor adicionando a Turma a sua coleo de Turmas, nada iria acontecer ao banco dedados. Isso parece no ter muito sentido, mas se voc prestar bem ateno, o Hibernate no tem comosaber qual dos dois lados foi atualizado, desse modo ele vai sempre atualizar os dois lados duas vezes,uma para cada classe da relao, o que seria desnecessrio. Usando inverse voc define de qual lado oHibernate deve esperar a atualizao e ele vai fazer a atualizao apenas uma vez. Lembre-se sempre deadicionar os objetos dos dois lados, pois em Java os relacionamentos no so naturalmente bidirecionais.

    Voltando a o n , percebemos que dentro dele ainda existem mais dois ns, e . O n representa a coluna da tabela relacionada (neste caso, Turma) que guarda a chaveestrangeira para a classe Professor, ns adicionamos o atributo column e o valor o nome da coluna,que neste caso Pessoa_Professor_id. No outro n, , ns definimos a classe a qualpertence essa coleo de objetos, que Turma (lembre-se sempre de usar o nome completo da classe,com o pacote).

    Depois do relacionamento um-para-muitos (1:N) vejamos agora como mapear um relacionamentomuitos-para-muitos (N:N). Em um banco de dados relacional, este tipo de associao faz uso de umatabela de relao, que guarda as chaves estrangeiras das duas tabelas associadas, como ocorre nonosso exemplo, onde tivemos que criar uma tabela Turma_has_Aluno, para poder mapear orelacionamento N:N entre as classes Turma e Aluno no banco de dados.

    Como voc j sabe, este tipo de associao tambm definida usando o n , vejamos ento onosso exemplo:

    Grupo de Usurios Java http://www.guj.com.br Pgina 8

  • Comunidade Livre Parabahttp://www.softwarelivre.pb.gov.br/

  • Comunidade Livre Parabahttp://www.softwarelivre.pb.gov.br/

    A maior parte do cdigo j conhecida, mas ainda existem algumas coisas que precisam seresclarecidas. Turma o lado um de dois relacionamentos um-para-muitos, um com a classe Professor eoutro com a classe Disciplina, para tornar essa associao bidirecional ns vamos utilizar o n , que modela o lado um de uma associao um-para-muitos (1:N). Neste n, ns inserimos osatributos name, que recebe o nome da propriedade, class, que recebe o nome da classe dapropriedade e column, que recebe o nome da coluna nesta tabela que guarda a chave estrangeira para aoutra tabela do relacionamento.

    O resto do mapeamento idntico aos outros mapeamentos que ns j estudamos, a nica diferena o lado da associao que ele est modelando. Os dois outros mapeamentos, de Disciplina e Curso, notrazem nenhuma novidade para o nosso estudo, portanto esteja livre para estudar os arquivos junto como resto do material de apoio.

    Cuidado com a descoberta automtica de tiposO Hibernate realmente facilita a vida do desenvolvedor com a descoberta automticados tipos das propriedades, mas em alguns momentos voc vai ter que definir o tipoda propriedade, para que o Hibernate no entre em conflito com o banco.

    Um tipo java.util.Date, por exemplo, pode simbolizar tanto um tipo DATE quantoum TIMESTAMP em um banco de dados, por isso, voc deve avisar ao Hibernate oque ele est mapeando, se um DATE ou um TIMESTAMP, no atributo type dapropriedade. Esse mesmo cuidado tambm deve ser tomado para CLOBs, BLOBs e aclasse java.util.Calendar.

    Configurando o Hibernate 3

    A engine do Hibernate pode ser configurada de trs modos diferentes, instanciando um objeto deconfigurao (org.hibernate.cfg.Configuration) e inserindo as suas propriedades programaticamente,usando um arquivo .properties com as suas configuraes e indicando os arquivos de mapeamentoprogramaticamente ou usando um arquivo XML (o hibernate.cfg.xml) com as propriedades deinicializao e os caminhos dos arquivos de mapeamento. Vejamos como configurar o Hibernate para onosso projeto:

    org.hibernate.dialect.MySQLDialect

    com.mysql.jdbc.Driver

    jdbc:mysql://localhost/hibernate?autoReconnect=true

    root

    1025000103000

    Grupo de Usurios Java http://www.guj.com.br Pgina 10

  • Comunidade Livre Parabahttp://www.softwarelivre.pb.gov.br/

    2

    true true true

    Na documentao do Hibernate voc pode verificar todas as opes de propriedades que podem serutilizadas e seus respectivos resultados, por isso ns vamos nos ater ao que importante paracomearmos a trabalhar. Vejamos as propriedades:

    hibernate.dialect: a implementao do dialeto SQL especfico do banco de dados a ser utilizado.

    hibernate.connection.driver_class: o nome da classe do driver JDBC do banco de dados que est sendoutilizado.

    hibernate.connection.url: a URL de conexo especfica do banco que est sendo utilizado.

    hibernate.connection.username: o nome de usurio com o qual o Hibernate deve se conectar ao banco.

    hibernate.connection.password: a senha do usurio com o qual o Hibernate deve se conectar ao banco.

    Essa segunda parte do arquivo so as configuraes do pool de conexes escolhido para a nossaaplicao. No nosso exemplo o pool utilizado o C3P0, mas voc poderia utilizar qualquer um dos poolsque so oferecidos no Hibernate ou ento usar um DataSource do seu servidor de aplicao. Na terceiraparte, esto algumas opes para ajudar a debugar o comportamento do Hibernate, a propriedadeshow_sql faz com que todo o cdigo SQL gerado seja escrito na sada default,hibernate.generate_statistics faz com que o Hibernate gere estatsticas de uso e possa diagnosticaruma m performance do sistema e hibernate.use_sql_comments adiciona comentrios ao cdigo SQLgerado, facilitando o entendimento das queries.

    A ltima parte do arquivo onde ns indicamos os arquivos de mapeamento que o Hibernate deveprocessar antes de comear a trabalhar, se voc esquecer de indicar um arquivo de mapeamento dequalquer classe, essa classe no vai poder ser persistida pela engine do Hibernate. Outro detalheimportante, que quando voc usa mapeamentos com Herana, o mapeamento pai deve sempre virantes do filho.

    Persistncia em cascataOs relacionamentos entre os objetos no Hibernate podem ser tratados com aes emcascata. Isso significaria, no nosso exemplo, que voc poderia inserir um objetoPessoa no banco de dados e depois associar um Endereco a ele, sem ter de indicar aoHibernate que este objeto deve ser persistido no banco de dados. Esse tipo de ao definido pelo atributo cascade nos ns de relacionamento (, ,etc). Ele pode assumir os seguintes valores:

    none : o Hibernate ignora a associao save-update : ele vai inserir ou atualizar automaticamente os objetos associados, quando o objeto

    raiz for inserido ou atualizado delete : ele vai deletar os objetos associados ao objeto raiz all : uma juno de delete e save-update all-delete-orphan : o mesmo que all, mas o Hibernate vai deletar qualquer objeto que tiver sido

    retirado da associao delete-orphan : faz com que o Hibernate veja se o objeto ainda faz parte da associao, se ele no fizer,

    vai ser deletado

    Grupo de Usurios Java http://www.guj.com.br Pgina 11

  • Comunidade Livre Parabahttp://www.softwarelivre.pb.gov.br/

    Entrando em Ao

    Agora que voc j est com o Hibernate configurado e pronto para funcionar, vamos entender omecanismo de persistncia dele. Para o Hibernate, existem trs tipos de objetos, objetos transient(transientes), detached (desligados) e persistent (persistentes). Objetos transient so aqueles queainda no tem uma representao no banco de dados (ou que foram excludos), eles ainda no estosobre o controle do framework e podem no ser mais referenciveis a qualquer momento, como qualquerobjeto normal em Java. Objetos detached tm uma representao no banco de dados, mas no fazemmais parte de uma sesso do Hibernate, o que significa que o seu estado pode no estar maissincronizado com o banco de dados. Objetos persistent so os objetos que tem uma representao nobanco de dados e que ainda fazem parte de uma transao do Hibernate, garantindo assim que o seuestado esteja sincronizado com o banco de dados (nem sempre, claro).

    No Hibernate, assim como no JDBC, existem os conceitos de sesso e transao. Uma sesso umaconexo aberta com o banco de dados, onde ns podemos executar queries, inserir, atualizar e deletarobjetos, j a transao a demarcao das aes, uma transao faz o controle do que acontece e podefazer um roolback, assim como uma transao do JDBC, se forem encontrados problemas.

    Edite o arquivo de configurao do Hibernate (hibernate.cfg.xml) com as suas informaes especficas(nome de usurio, senha, URL de conexo, etc), coloque ele na raiz do seu classpath, junto com asclasses compiladas e os arquivos de mapeamento, porque ns vamos colocar o Hibernate pra funcionar(tenha certeza de que o seu classpath est configurado corretamente, com todos os arquivosnecessrios).

    Primeiro, vamos criar uma classe para configurar e abrir as sesses do Hibernate, o cdigo simples:

    //Arquivo HibernateUtility.java

    import org.hibernate.Session;import org.hibernate.SessionFactory;import org.hibernate.cfg.Configuration;

    public class HibernateUtility {

    private static SessionFactory factory; static { try { factory = new Configuration().configure().buildSessionFactory(); } catch (Exception e) { e.printStackTrace(); factory = null; } } public static Session getSession() { return factory.openSession(); } }

    O bloco esttico (as chaves marcadas como static) instancia um objeto de configurao do Hibernate(org.hibernate.cfg.Configuration), chama o mtodo configure() (que l o nosso arquivohibernate.cfg.xml) e depois que ele est configurado, criamos uma SessionFactory, que a classe quevai ficar responsvel por abrir as sesses de trabalho do Hibernate. Faa um pequeno teste pra tercerteza de que tudo est funcionando:

    //Arquivo Teste.java

    Grupo de Usurios Java http://www.guj.com.br Pgina 12

  • Comunidade Livre Parabahttp://www.softwarelivre.pb.gov.br/

    public class Teste {

    public static void main(String[] args) {

    Session sessao = HibernateUtility.getSession(); //Abrindo uma sessoTransaction transaction = sessao.beginTransaction(); //Iniciando uma transao

    Curso curso = new Curso(); //Instanciando um objeto transiente

    curso.setNome("Desenvolvimento de Software"); //Preenchendo as propriedades do objetocurso.setDescricao("Curso s pra programadores");

    sessao.save(curso); //Transformando o objeto transiente em um objeto//persistente no banco de dados

    transaction.commit(); //Finalizando a transaosessao.close(); //Fechando a sesso

    }}

    Se ele no lanou nenhuma exceo, o seu ambiente est configurado corretamente. Vamos entenderagora o que foi que aconteceu neste cdigo, primeiro ns inicializamos a SessionFactory, dentro do blocoesttico na classe HibernateUtility, depois que ela inicializada, o mtodo getSession() retorna uma novasesso para o cdigo dentro do main(). Aps a sesso ter sido retornada, ns iniciamos uma transao,instanciamos um objeto Curso, preenchemos as suas propriedades e chamamos o mtodo save() nasesso. Aps o mtodo save(), finalizamos a transao e fechamos a sesso. Acabamos de inserir umregistro no banco de dados sem escrever nenhuma linha de SQL, apenas com a chamada de um mtodo.

    O cdigo de aplicaes que usam o Hibernate costumam mostrar esse mesmo comportamento, abrirsesso, inciciar transao, chamar os mtodos save(), update(), get(), delete(), etc, fechar a transao edepois a sesso, um comportamento muito parecido com o de aplicaes JDBC comuns, a diferena que no escrevemos nem uma linha sequer de SQL para tanto.

    Nomes das classesNa maioria dos exemplos, ns no inclumos os imports nem usamos os nomescompletos das classes para facilitar a leitura, veja aqui alguns dos nomes completosdas classes que voc vai encontrar:

    Session = org.hibernate.Session SessionFactory = org.hibernate.SessionFactory Configuration = org.hibernate.cfg.Configuration Transaction = org.hibernate.Transaction Query = org.hibernate.Query Criteria = org.hibernate.Criteria Criterion = org.hibernate.criterion.Criterion Restrictions = org.hibernate.criterion.Restrictions

    Fazendo pesquisas no banco usando o Hibernate

    Agora que voc j sabe mapear e configurar a fera, podemos passar para uma das partes maisimportantes do funcionamento do framework, as pesquisas. Existem trs meios de se fazer buscasusando o Hibernate, usando a sua linguagem prpria de buscas, a Hibernate Query Language (HQL),usando a sua Criteria Query API (para montar buscas programaticamente) e usando SQL puro. Amaioria das suas necessidades deve ser suprida com as duas primeiras alternativas, o resto, voc semprepode usar SQL pra resolver.

    A HQL uma extenso da SQL com alguns adendos de orientao a objetos, nela voc no vaireferenciar tabelas, vai referenciar os seus objetos do modelo que foram mapeados para as tabelas dobanco de dados. Alm disso, por fazer perquisas em objetos, voc no precisa selecionar as colunas dobanco de dados, um select assim: select * from Turma em HQL seria simplesmente from Turma,porque no estamos mais pensando em tabelas e sim em objetos.

    Grupo de Usurios Java http://www.guj.com.br Pgina 13

  • Comunidade Livre Parabahttp://www.softwarelivre.pb.gov.br/

    A Criteria Query API um conjunto de classes para a montagem de queries em cdigo Java, vocdefine todas as propriedades da pesquisa chamando os mtodos e avaliaes das classes relacionadas.Como tudo definido programaticamente, voc ganha todas as funcionalidades inerentes daprogramao orientada a objetos para montar as suas pesquisas e ainda garante a completaindependncia dos bancos de dados, pois a classe de dialeto SQL do seu banco vai se encarregar detraduzir tudo o que voc utilizar.

    Antes de ver os exemplos propriamente ditos, vejamos como criar um objeto que implemente ainterface Query ou Criteria. Para instanciar um desses objetos, voc vai ter que abrir uma sesso doHibernate, como ns j vimos na listagem do arquivo Teste.java. Vejamos como ficaria o cdigo:

    Session sessao = HibernateUtility.getSession();Transaction tx = sessao.beginTransaction();Query select = sessao.createQuery("from Turma");List objetos = select.list();System.out.println(objetos);tx.commit();sessao.close();

    O cdigo ainda segue aquela mesma seqncia da listagem anterior, abrir uma sesso, iniciar umatransao e comear a acessar o banco de dados. Para criar uma query, ns chamamos o mtodocreateQuery(String query) na sesso, passando como parmetro o String que representa a query. Depoisdisso, podemos chamar o mtodo list(), que retorna um List com os objetos resultantes da query.Usando a Criteria API, o cdigo ficaria desse modo:

    Session sessao = HibernateUtility.getSession();Transaction tx = sessao.beginTransaction();

    Criteria select = sessao.createCriteria(Turma.class);List objetos = select.list();

    System.out.println(objetos);

    tx.commit();sessao.close();

    Veja que apenas a linha onde ns crivamos a query mudou. Agora, em vez de chamar o mtodocreateQuery(String query), ns chamamos o mtodo createCriteria(Class clazz), passando comoparmetro a classe que vai ser pesquisada, que no nosso caso Tuma.

    Outro complemento importante do Hibernate o suporte a paginao de resultados. Para paginar osresultados, ns chamamos os mtodos setFirstResult(int first) e setMaxResults(int max). O primeiromtodo indica de qual posio os objetos devem comear a ser carregados, o segundo indica o mximode objetos que devem ser carregados. Estes mtodos esto presentes tanto na interface Query quantona interface Criteria. Vejamos como ns deveramos proceder para carregar apenas as dez primeirasturmas do nosso banco de dados:

    Session sessao = HibernateUtility.getSession();Transaction tx = sessao.beginTransaction();

    Criteria select = sessao.createCriteria(Turma.class);select.setFirstResult(0);select.setMaxResults(10);

    List objetos = select.list();

    System.out.println(objetos);

    tx.commit();sessao.close();

    Grupo de Usurios Java http://www.guj.com.br Pgina 14

  • Comunidade Livre Parabahttp://www.softwarelivre.pb.gov.br/

    Veja que ns chamamos os mtodos setFirstResult() e setMaxResults() antes de listar os objetos daquery e lembre-se tambm que a contagem de resultados (assim como os arrays) comea em zero, noem um.

    Uma propriedade especfica da HQL, que foi herdada do JDBC, o uso de parmetros nas queries.Assim como no JDBC, os parmetros podem ser numerados, mas tambm podem ser nomeados, o quesimplifica ainda mais o uso e a manuteno das queries, porque a troca de posio no vai afetar ocdigo que as usa. Vejamos um exemplo do uso de parmetros:

    Session sessao = HibernateUtility.getSession();Transaction tx = sessao.beginTransaction();

    Query select = sessao.createQuery("from Turma as turma where turma.nome = :nome");select.setString("nome", "Jornalismo");

    List objetos = select.list();

    System.out.println(objetos);

    tx.commit();sessao.close();

    Nesse nosso novo exemplo, tivermos mais algumas adies a query HQL. A primeira o uso do as,que serve para apelidar uma classe no na nossa expresso (do mesmo modo do as em SQL), ele no obrigatrio, o cdigo poderia estar from Turma turma ... e ele funcionaria normalmente. Outra coisa ase notar, o acesso as propriedades usando o operador . (ponto), voc sempre acessa as propriedadesusando esse operador. E a ltima parte o parmetro propriamente dito, que deve ser iniciado com :(dois pontos) para que o Hibernate saiba que isso um parmetro que vai ser inserido na query. Vocinsere um parmetro nomeado, usando o mtodo set correspondente ao tipo de parmetro, passandoprimeiro o nome com o qual ele foi inserido e depois o valor que deve ser colocado.

    E se voc tambm no gosta de ficar metendo cdigo SQL no meio do seu programa, porque deveriameter cdigo HQL? O Hibernate facilita a externalizao de queries HQL (e at SQL) com os ns e nos arquivos de mapeamento. Vamos adicionar uma query no mapeamento da classe turma(o arquivo Turma.hbm.xml):

    Essas linhas adicionadas no arquivo de mapeamento vo instruir o Hibernate a criar umPreparedStatement para esse select, fazendo com que ele execute mais rpido e possa ser chamado dequalquer lugar do sistema. Voc deve preencher o atributo name com o nome pelo qual esta query deveser chamada na aplicao e no corpo do n voc deve colocar o cdigo da query, de preferncia dentrode uma tag CDATA, pra evitar que o parser XML entenda o que est escrito na query como informaespara ele. Veja como executar uma named query:

    Session sessao = HibernateUtility.getSession();Transaction tx = sessao.beginTransaction();

    Query select = sessao.getNamedQuery("buscarTurmasPeloNome");select.setString("nome", "Jornalismo");

    List objetos = select.list();

    System.out.println(objetos);

    tx.commit();sessao.close();

    A nica diferena para as outras listagens que em vez de escrevermos a query dentro do cdigoJava, ela ficou externalizada no arquivo de mapeamento. Para instanciar o objeto, chamamos o mtodogetNamedQuery(String name), passando como parmetro o nome da query definido no atributo name noarquivo XML.

    Grupo de Usurios Java http://www.guj.com.br Pgina 15

  • Comunidade Livre Parabahttp://www.softwarelivre.pb.gov.br/

    Adicionando restries as pesquisas

    Vamos ver agora como adicionar restries as nossas pesquisas no Hibernate. Os exemplos vo seguiruma dinmica simples, com uma verso em HQL e como o mesmo exemplo poderia ser feito usando aAPI de Criteria.

    A HQL e a API de Criteria suportam todos os operadores de comparao da SQL ( , , =, =,between, not between, in e not in), vejamos um exemplo em HQL:

    from Aluno al where al.endereco.numero >= 50

    O uso dos operadores de comparao segue a mesma sintaxe da linguagem SQL, usando Criteria, essamesma query poderia ser expressa da seguinte maneira:

    Criteria select = sessao.createCriteria(Aluno.class);

    select.createCriteria("endereco").add( Restrictions.ge( "numero", new Integer(10) ) );

    Ns criamos a o objeto Criteria usando a classe Aluno, mas a nossa restrio para a propriedadenumero da classe Endereco que est associada a classe Aluno, ento temos que descer um nvel, parapoder aplicar a restrio a propriedade numero de endereco. Usando Criteria, voc pode usar osmtodos estticos da classe org.hibernate.criterion.Restrictions para montar expresses.

    Os operadores lgicos (e os parnteses) tambm esto a sua disposio e em HQL eles continuamcom a mesma sintaxe do SQL. Voc pode usar or, and e parnteses para agrupar as suas expresses.Vejamos um exemplo:

    from Endereco end where ( end.rua in (Epitcio Pessoa, Ipiranga) )

    or ( end.numero between 1 and 100 )

    Passando para Criteria:

    Criteria select = sessao.createCriteria(Endereco.class);String[] ruas = {"Epitcio Pessoa", "Ipiranga"};

    select.add(

    Restrictions.or(

    Restrictions.between("numero", new Integer(1), new Integer(100) ),Restrictions.in( "rua", ruas )

    ) );

    O cdigo usando Criteria muito mais longo do que a expresso em HQL e tambm menos legvel.Procure utilizar Criteria apenas quando for uma busca que est sendo montada em tempo de execuo,se voc pode prever a busca, use named queries e parmetros para deixar o eu cdigo mais limpo emais simples.

    Outra parte importante das pesquisas so as funes de pesquisa em Strings. Voc pode usar LIKE eos smbolos % e _, do mesmo modo que eles so utilizados em SQL. Vejamos um exemplo:

    from Curso c where c.nome like Desenvolvimento%

    Em Criteria:

    Criteria select = sessao.createCriteria(Curso.class);select.add( Restrictions.like("nome", "Desenvolvimento", MatchMode.START) );

    Alm disso, voc ainda pode ordenar as suas pesquisas, em ordem ascendente ou descendente. Comonos exemplos a seguir:

    from Aluno al order by al.nome asc

    Grupo de Usurios Java http://www.guj.com.br Pgina 16

  • Comunidade Livre Parabahttp://www.softwarelivre.pb.gov.br/

    Em Criteria:

    Criteria select = sessao.createCriteria(Aluno.class);select.addOrder( Order.asc("nome") );

    Inicializao tardia (lazy-loading)Quando voc faz uma pesquisa em uma tabela no banco de dados, nonecessariamente pesquisa tambm pelas tabelas que esto relacionadas, porque vocpode estar carregando informaes que no so necessrias neste cenrio da suaaplicao. O Hibernate tambm no inicializa os relacionamentos 1:N e N:Nautomaticamente, porque ele pode estar caindo nesse caso de carregar objetos queno so necessrios neste caso.

    Existem dois modos de se definir a inicializao de relacionamentos 1:N e N:N, oprimeiro definir o atributo outer-join da associao (um , por exemplo)para true. Isso vai fazer com que a coleo de objetos seja sempre inicializadacompletamente antes de devolver o objeto. Mas isso s funciona para buscas feitasusando a Criteria API, ou os mtodos get() e load().

    O outro modo (e mais indicado) fazer uma left join entre os objetos, em umabusca HQL, assim voc s vai carregar a coleo quando ela for necessria. Vejamoscomo fazer isso no nosso modelo, carregando as Disciplinas de um Curso:

    from Curso cursoleft join fetch curso.disciplinas

    where curso.nome = :nome

    Veja que ns adicionamos left join fetch a query e depois indicamos a coleo quedeveria ser inicializada, neste caso curso.disciplinas. Assim, quando essa busca forexecutada, vai retornas os objetos Curso com as suas respectivas Disciplinasintnciadas.

    Concluso

    O Hibernate um framework incrvel, que facilita o desenvolvimento de aplicaes que acessambancos de dados, fazendo com que o programador se preocupe mais com o seu modelo de objeto e seuscomportamentos, do que com as tabelas do banco de dados. O Hibernate tambm evita o trabalho deescrever dzias de cdigo repetido para fazer as mesmas coisas, como inserts, selects, updates edeletes no banco de dados, alm de ter duas opes para se montar buscas complexas em grafos deobjetos e ainda uma sada para o caso de nada funcionar, usar SQL.

    Alm de mecanismo de mapeamento objeto/relacional, o Hibernate tambm pode trabalhar com umsistema de cache das informaes do banco de dados, aumentando ainda mais a performance dasaplicaes. O esquema de cache do Hibernate complexo e totalmente extensvel, existindo diversasimplementaes possveis, cada uma com suas prprias caractersticas. E junto com isso, ele tambmtem um gerenciador de verses prprio.

    Entretanto, como j foi dito no incio do artigo, ele no a soluo perfeita para todos os problemas,aplicaes que fazem uso intenso de stored procedures, triggers, user defined functions e outrasextenses especficas dos bancos de dados, normalmente no vo se beneficiar do mecanismo oferecidopelo Hibernate. Alm disso, aplicaes que tem uma alta freqncia de movimentos em massa, comoseqncias de inserts, updates e deletes terminaria por perder performance, graas a instanciao ecarregamento de diversos objetos na memria.

    Este artigo apenas um aperitivo para o que o Hibernate pode realmente fazer por voc, consulte areferncia oficial, leia os JavaDocs e, se puder, compre o livro do Gavin King e do Christian Bauer,Hibernate em Ao (originalmente Hibernate in Action), um adendo valioso a sua biblioteca, noapenas pelo contedo relacionado ao Hibernate, mas pelas boas prticas de desenvolvimento earquitetura de sistemas.

    Grupo de Usurios Java http://www.guj.com.br Pgina 17

  • Comunidade Livre Parabahttp://www.softwarelivre.pb.gov.br/

    Maurcio Linhares ([email protected]) estudante de Desenvovimento de Software para a Internet noCEFET-PB, de Comunicao Social (com habilitao em Jornalismo) na UFPB e membro do grupo Comunidade LivreParaba (http://www.softwarelivre.pb.gov.br/).

    Referncias e recursos Hibernate In Action. Bauer, Christian. King, Gavin. Editora Manning, 2004 Hibernate: A Developers Notebook. Elliot, James. Editora OReilly, 2004 Documentao do Hibernate 3 , vrios autores.

    DbDesigner (ferramenta de criao de bancos de dados MySQL) Jude (ferramenta de modelagem UML Java)

    Grupo de Usurios Java http://www.guj.com.br Pgina 18