Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
Objetivos
Aprender sobre os conceitos de persistncia relacionados ao Hibernate Aprender como recuperar os dados e efetuar consultas de maneira eficientemente no Hibernate
Como Hibernate oferece um sistema transparente de persistncia, as classes no sabem de sua capacidade de persistncia Por outro lado, a aplicao que usa os objetos, os utiliza em estados diferentes
Transientes, antes de serem gravados em meio persistente Persistentes, quando esto armazenados Desligados, quando suas instncias so manipuladas sem afetar a base de dados
Diagrama de estados
Objetos transientes
Seu estado transiente (ainda no foram armazenados no banco e deixaro de existir assim que perderem sua referncia) Session.delete() sobre um objeto persistente torna-o transiente Rollback no recupera seu estado anterior
Objetos referenciados por instncias transientes so (por default) tambm transientes Para mudar para o estado persistente preciso
Passar o objeto como argumento de um Session.save(), ou Criar a referncia a partir de uma instncia persistente
Objetos persistentes
Uma instncia persistente uma instncia com uma identidade no banco de dados
Tem uma chave primria como identificador Objeto criado com new e armazenado com Session.save() Objeto criado a partir da referncia de uma instncia persistente Objeto obtido a partir de um query no banco
Podem ser
Seu estado sincronizado com o banco ao fim da transao Automatic dirty checking (transparente ao usurio) usado como estratgia de atualizao eficiente de dados
Quando a sesso fechada (Session.close()) todas as instncias ainda mantm seu estado, mas no esto mais sincronizadas com o banco
Podem ficar obsoletas se houver mudana no banco Podem mudar de estado, que no ser refletido no banco Mas, a qualquer momento, a sesso pode ser reativada, tornando o objeto persistente e sincronizando seu estado
Objetos desligados so teis para transportar o estado de objetos persistentes para outras camadas
Camada de apresentao, em substituio aos DTOs (Data Transfer Objects, tambm chamados de Value Objects)
4) Grave o objeto
session.save(user);
5) Cometa a transao
tx.commit();
6) Feche a sesso
session.close();
Qualquer alterao no seu estado no afeta o banco Para relig-lo pode-se usar update()
user.setPassword("secret"); // objeto desligado Session sessionTwo = sessions.openSession(); Transaction tx = sessionTwo.beginTransaction(); sessionTwo.update(user); user.setUsername("jonny"); // objeto persistente tx.commit(); sessionTwo.close();
A forma mais simples de recuperar um objeto pelo identificador, usando o comando get():
Session session = sessions.openSession(); Transaction tx = session.beginTransaction(); int userID = 1234; User user = (User) session.get(User.class, new Long(userID)); tx.commit(); session.close();
Uma vez que a sesso foi fechada, o objeto uma instncia desligada, e pode ser repassada para outras camadas (apresentao, por exemplo) Se o objeto no existir, a chamada get() retorna null
Quaisquer modificaes no seu estado sero sincronizadas com o banco de dados Hibernate automaticamente verifica e grava as mudanas ocorridas dentro de uma sesso (automatic dirty checking) As mudanas tornam-se permanentes ao cometer a transao O objeto torna-se desligado quando a sesso fecha
Session session = sessions.openSession(); Transaction tx = session.beginTransaction(); int userID = 1234; User user = (User) session.get(User.class, new Long(userID)); user.setPassword("secret"); tx.commit(); session.close();
Para isto preciso usar o gerente de persistncia e chamar o mtodo delete() Quando a sesso terminar o objeto ser considerado um mero objeto Java transiente (cujo estado ser perdido assim que o coletor de lixo atuar)
Session session = sessions.openSession(); Transaction tx = session.beginTransaction(); int userID = 1234; User user = (User) session.get(User.class, new Long(userID)); session.delete(user); tx.commit(); session.close();
Para tornar um objeto desligado transiente, no preciso lig-lo ou fazer update() Basta chamar delete() sobre sua instncia
Session session = sessions.openSession(); Transaction tx = session.beginTransaction(); session.delete(user); tx.commit(); session.close();
beginTransaction()
Demarca o incio de uma transao. Retorna um objeto Transaction que deve chamar commit() ou rollback() no final da transao. Fecha e desconecta a sesso Desconecta a sesso da conexo JDBC atual sem fech-la. Obtm uma nova conexo JDBC para a sesso ou tenta conectar a uma conexo JDBC, se passada como argumento Sincroniza a camada de objetos com a camada de dados. Este mtodo chamado automaticamente quando a transao cometida.
close()
disconnect()
reconnect()
flush()
save(Object)
Torna persistente o objeto passado como argumento Insere (tornando persistente) ou atualiza o objeto passado como argumento Atualiza o objeto passado como argumento Remove os dados de um objeto do banco, tornando-o transiente Carrega e retorna a instncia de objeto identificado pela classe e identificador Recarrega do banco os dados da instncia passada como argumento Remove o objeto passado como argumento do cache do sistema
saveOrUpdate(Object)
update(Object)
delete(Object instancia)
load(classe, identificador)
refresh(Object)
evict(Object)
Recuperao de dados
Pelo identificador Navegando na rvore de objetos [ ex: usuario.getEndereco().getCidade() ] Usando HQL Usando a API Criteria Usando SQL nativo
Ambos utilizam o cache, e evitam acessar o banco se no for necessrio Devolve o objeto se existir e null se o objeto no for encontrado no banco ou no cache Devolve o objeto ou um proxy para o objeto se existirem, ou causa exceo se nenhum for encontrado no banco ou no cache O proxy pode apontar para objeto que ainda ou no mais existe
HQL
Assemelha-se a ODMG OQL e EJB-QL mas adaptado para uso em bancos de dados SQL No uma linguagem de manipulao de dados (como SQL); no serve para inserir, remover, atualizar usada apenas para recuperao de objetos
Exemplo
Query q = session.createQuery("from User u where u.firstname = :fname"); q.setString("fname", "Max"); List result = q.list();
HQL
Pesquisas com navegao do grafo de objetos Recuperao seletiva de propriedades dos objetos selecionados (sem ter que carregar objeto inteiro) Ordenao de resultados Paginao de resultados Agregao com group by, having, e funes sobre agregados como sum, count, min e max Outer joins ao recuperar mltiplos objetos por registro Chamadas a funes SQL definidas pelo usurio Subqueries
QBC = Query By Criteria Queries podem ser expressos usando uma API em vez de usar HQL
Evita uso de strings Validao feita em tempo de compilao Enfoque mais orientado a objetos Mais difcil de ler ( Java e no HQL) Em HQL: from User u where u.firstname = :fname Em QBC:
Exemplo
Talvez o problema mais difcil de solucionar em ORM: acesso eficiente a dados relacionais Aplicao prefere tratar os dados como um grafo de objetos interligados por associaes
mais fcil fazer vrios pequenos queries (performance baixa) Alternativa: escrever queries para cada associao (muito complexo e pouco flexvel)
Hibernate permite especificar uma estratgia de recuperao default (no mapeamento) que pode ser sobreposta em tempo de execuo
Estratgias de recuperao
Fetching strategies Estratgias para qualquer associao (nos metadados e em tempo de execuo)
Lazy fetching objeto associado s recuperado quando chamado Eager fetching objeto associado recuperado atravs de SQL outer join Batch fetching acessa uma coleo de objetos prdeterminada
Lazy fetching
O restante do grafo pode ser carregado medida em que for necessrio Vai requer mais chamadas ao banco posteriormente, mas pode ser que elas no sejam necessrias Pode ser otimizada com Batch Fetching
A estratgia pode depois ser sobreposta em tempo de execuo por estratgias mais vidas
LazyInitializationException
A forma mais simples de evit-lo, realizar tudo dentro da sesso (o commit() sincroniza os dados e evita a inconsistncia) Sabendo-se do estado do objeto, os dados podem ser recuperados em outra sesso (quando voltar a ser persistente)
s = sessions.openSession(); User u = (User) s.createQuery("from User u where u.name=?).setString(userName).list().get(0); Map permissions = u.getPermissions(); s.connection().commit(); s.close(); Integer accessLevel = (Integer) permissions.get("accounts"); // Error!
uma soluo rpida para otimizar lazy fetching um lazy menos lazy: usurio define quantos nveis de associaes devem ser carregadas
Hibernate procura as outras instncias associadas coleo e tenta carreg-las ao mesmo tempo Pode ser melhor que lazy simples
Eager fetching
uma soluo que ajuda a reduzir a carga sobre o banco de dados de forma mais inteligente que Batch Fetching
Permite que se especifique explicitamente quais objetos associados devem ser carregados juntos com o objeto que os referencia Os objetos associados podem ento ser retornados em nica requisio
Otimizao de performance em Hibernate freqentemente usa esse tipo de estratgia em tempo de execuo para um query em particular
A seleo de uma estratgia de recuperao de dados default feita atravs de atributos no XML do arquivo de mapeamento. Mapeamentos de coleo diferem dependendo do tipo de associaes.
Colees e associaes de muitos para muitos comportam-se diferentemente de associaes singulares -to-one.
Usado do lado oposto da associao O outro lado escolhe lazy fetching (ou immediate fetching por omisso) outer-join=auto (default). O comportamento lazy, se o outro lado (singular) da associao especificar, ou eager, se no especificado. outer-join=true Comportamento sempre eager para esta associao (logo diferentes associaes para mesmo objeto podem ter estratgias diferentes) outer-join=false Se o objeto tiver sido mapeado como lazy, ocorre lazy fetching, caso contrrio, immediate fetching (SQL select)
Opes
Exemplo:
<many-to-one name="item" class="Item" outer-join="true">
Em colees
Lazy
Batched Lazy
Eager
Consultas HQL
O query mais simples possvel Os resultados de um query podem ser lidos em pginas O query abaixo l 10 pginas, a partir da primeira pgina
Query query = session.createQuery("from User u order by u.name asc"); query.setFirstResult(0); query.setMaxResults(10); List results = query.list();
Listagem de resultados
List result = session.createQuery("from User").list();
Passagem de parmetros
Risco de segurana: basta esquecer de fechar a aspa Longos queries ficam ilegveis
O ideal passar parmetros que sero ligados ao query Parmetros podem ser passados duas formas
Passagem de parmetros
Na verdade, muitas vezes melhor que no apaream Podem ficar nos metadados e serem chamados pelo nome
Mas antes, preciso que ele seja declarado em algum arquivo de mapeamento (ex: Item.hbm.xml):
<query name="findItemsByDescription"><![CDATA[ from Item item where item.description like :description ]]></query>
Aliases
Aliases (apelidos) so usados para que se possa ter uma referncia para acessar propriedades das instncias recuperadas
from Livro
Mas o as opcional
from Livro livro
Queries polimrficos
BillingDetails
pois os resultados so classes concretas CreditCard BankAccount BankAccount e CreditCard Queries polimrficos podem ser feitos em qualquer classe, no apenas em classes mapeadas O query abaixo retorna todas as instncias mapeadas
from java.lang.Object
Como em SQL, HQL define restries de um query atravs da clusula where, que suporta vrias expresses. Por exemplo, a expresso de equivalncia:
from User u where u.email = 'foo@hibernate.org
lgica ternria
HQL suporta os mesmos operadores que SQL Queries Criteria: expresses na classe Expression
No h suporte para expresses aritmticas via API (s via HQL) Comparao: =, <>, <, >, >=, <=, between, not between, in, not in Nulidade: is null, is not null Aritmticos: +, -, /, *, %, parnteses
Operadores do HQL:
Exemplos
Bid bid where bid.amount between 1 and 10 Bid bid where bid.amount > 100 User u where u.email in ( "foo@abc.org", "bar@abc.org" ) User u where u.email is null Bid bid where ( bid.amount / 0.71 ) - 100.0 > 0.0
O smbolo _ representa um caractere O smbolo % representa vrios caracteres HQL: from User u where u.firstname like "G%" Criteria: session.createCriteria(User.class)
Exemplos
.add(Expression.like("firstname","G%"))
Mais HQL
Operadores lgicos: and, or, parnteses, etc. servem para argupar expresses
from User user where ( user.firstname like "G%" and user.lastname like "K%" ) or user.email in ( "foo@abc.org", "bar@abc.org" )
Joins
Joins (junes) so usados para combinar dados de duas ou mais tabelas relacionadas H quatro tipos de joins possveis
Inner join Left outer join Right outer join Full join ANSI: juno de tabelas atravs de propriedade comum com condio de join na clusula on Theta: produto cartesiano de tabelas com condio de join na clusula where
Left outer join (ou left join) - Inclui tambm Itens que no tm Bids
Right outer join (right join) - permite valores nulos na tabela esquerda (inclui Bids sem Itens mas no itens sem Bids) no faz sentido neste caso (lance sem item) Full join - permite valores nulos nas duas tabelas (inclui Bids que no tm Itens e itens que no tm Bids) tambm no faz sentido neste caso
Joins em HQL
Elas podem ser deduzidas das associaes entre objetos automaticamente Queries ficam mais simples e legveis Fetch join (outer, agressivo) na clusula from Join comum (inner, lazy) na clusula from Join theta-style (produto cartesiano) na clusula where Join por associao explcita
Fetch join
Recupera objeto inteiro (com associaes inicializadas.) Exemplo HQL: Retorna lista de
from Item item left join fetch item.bids where item.description like '%gc%
objetos com colees j inicializadas
Freqentemente necessrio aplicar restries a tabelas combinadas com join. Isto pode ser feito atribundo um alias ao join:
from Item item join item.bids bid where item.description like '%gc% and bid.amount > 100
Em vez de uma lista de Item, retorna uma lista de Object[] Retorna uma lista de arrays {item, bid} (Se fosse um fetch join, retornaria uma lista de Item com coleo de bids inicializada) Um Item pode aparecer mltiplas vezes (uma vez para cada Bid associado)
Clusula select
Select opcional em HQL (mas no em SQL) A ausncia do select equivale ao SQL select *
Para que o inner join do exemplo anterior devolva apenas os itens (e no uma lista de Object[] com par item-bid) pode-se usar select:
select item from Item item join item.bids bid
Exemplo
Query q = session.createQuery("select i from Item i join i.bids b"); Iterator items = q.list().iterator(); while ( items.hasNext() ) { Item item = (Item) items.next(); }
Agora temos uma lista de Items contendo apenas os Items que tm Bids (inner join)
Joins implcitos
Ocorrem em associaes *-para-um (caminho convergente) e nunca em caminhos *-para-muitos O HQL a seguir causa trs joins em SQL
from Bid bid where bid.item.category.name like 'Laptop%' and bid.item.successfulBid.amount > 100
Ou ainda
from Bid as bid join bid.item as item join item.category as cat join item.successfulBid as winningBid where cat.name like 'Laptop% and winningBid.amount > 100
Permite recuperar todas as combinaes possveis de instncias de duas ou mais classes til em classes no associadas
Condio de join deve estar na clusula where Apenas inner-join pode ser usado neste caso
Produto cartesiano
Exemplo
Query query = session.createQuery("from User user, LogRecord log " + "where user.username = log.username") Iterator i = query.list().iterator(); while ( i.hasNext() ) { Object[] pair = (Object[]) i.next(); Condio de join User user = (User) pair[0]; LogRecord log = (LogRecord) pair[1]; }
Comparao de identificadores
Queries de relatrios
Instncias no so importantes, mas valores selecionados, agrupados e organizados de certas instncias Dependem de recursos de seleo e agrupamento Usa-se clusulas select e group by / having.
Quais os dados desejados no resultado? O query abaixo seleciona trs propriedades de dois objetos
Os dados sero retornados em um vetor de Object[] de tamanho 3. Os resultados no so entidades (so valores) e no so transacionais (sero usados para leitura, apenas)
Query query = session.createQuery("select item.id, item.description, bid.amount " + "from Item item join item.bids bid where bid.amount > 100"); Iterator i = query.list().iterator(); while ( i.hasNext() ) { Object[] row = (Object[]) i.next(); Long id = (Long) row[0]; String description = (String) row[1]; BigDecimal amount = (BigDecimal) row[2]; ItemRow itemRow = new ItemRow(id, description, amount); }
Instanciamento dinmico
Hibernate permite o instanciamento dinmico de objetos que so povoados pelos resultados do query
Evita o uso de vetores de objetos necessrio que exista uma classe e construtor previamente construda
class ItemRow { public ItemRow(Long id, String description, BigDecimal amount) {...} ... } Query query = session.createQuery( "select new ItemRow(item.id, item.description, bid.amount)" + "from Item item join item.bids bid where bid.amount > 100"); Iterator i = query.list().iterator(); while ( i.hasNext() ) { ItemRow row = (ItemRow) i.next(); // ... fazer alguma coisa }
Distinct
Com o uso da clusula select, os resultados de um query no mais tem garantia de serem distintos A seguinte query pode retornar Items repetidos
select item.description from Item item
Funes agregadas
Integer count = (Integer) session.createQuery("select count(*) from Item").uniqueResult(); BigDecimal sum = (BigDecimal) session.createQuery("select sum(item.successfulBid.amount) " +"from Item item").uniqueResult(); BigDecimal[] minmax = (BigDecimal[]) session.createQuery("select min(bid.amount), max(bid.amount) +"from Bid bid where bid.item.id = 1") .uniqueResult(); BigDecimal min = minmax[0]; BigDecimal max = minmax[1];
Agrupamento
Se houver funes agregadas no select, no pode haver seleo de outros elementos, a menos que haja uma clusula group by
select bid.item.id, count(bid), avg(bid.amount) from Bid bid where bid.item.successfulBid is null group by bid.item.id select bidItem.id, count(bid), avg(bid.amount) from Bid bid join bid.item bidItem where bidItem.successfulBid is null group by bidItem.id select item.id, count(bid), avg(bid.amount) from Item item fetch join item.bids bid where item.successfulBid is null group by item.id
Um fetch (outer) join; o agrupamento teve que ser feito usando item.id
Grupos requerem o uso de pelo menos dois aliases no select (a funo e a propriedade de agrupamento) Sempre que a clusula select tem mltiplos aliases, o Hibernate devolve o resultado como (tuplas)vetores de Object
Chato de manipular; inseguro quanto ao tipo Ideal usar select new e instanciar objetos dinamicamente
...agora acabo!
Referncias