Arquivos de sites

Quando usar o fetch.LAZY e o fetch.EAGER

Alguns conceitos básicos:

  • EAGER – Tradução ->
  1. Ansioso
  2. Impaciente
  3. Ardente
  class NotaFiscal {
  ...
  @OneToMany(fetch=FetchType.EAGER)
  List items;
  }

Imagine que quando você usa o EAGER e dá um get num objeto, ele traz tudo que está dentro do objeto, ou seja, se há um relacionamento 1 para N, no objeto será carregado todas as referências(N) dele. Se sua aplicação depende de performance, este pode ser um problema, pois isto ocupará um grande espaço de memória carregando todas as listas/dependências do objeto.

  • LAZY – Tradução:
  1. Preguiçoso
  2. Indolente
  3. Lento
  4. Ocioso
  5. Vadio
  @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "tabela_despesas", nullable = false)
    public Despesa getRelatorioDespesa() {
        return this.relatorioDespesa;
    }

Desse modo, quando acessamos o objeto ele não traz instantaneamente todas as dependências. Somente quando precisamos do atributo dependente é que a pesquisa (select ou JOIN) é feito, economizando memória. Para que o LAZY faça este select/JOIN é necessário declarar o fetch, dizer como será a pesquisa, se via Selec ou JOIN e você gera então a consulta.

O Hibernate tira proveito de proxies dinâmicas: ele te devolve objetos que fingem ser listas nesse caso, e quando você invoca algum método deles, o Hibernate então faz a respectiva query para carregar o relacionamento. Caelum

Lazy diz QUANDO trazer.lazy=”true” – Traga quando eu precisar ( ou seja. Quando eu acessar ) lazy = “false” – Traga junto com o objeto principal

  • Fetch – Tradução->
  1. buscar
  2. ir buscar
  3. trazer

Fetch diz COMO trazer.fetch = “select” – Faça um select pra pegar esse atributo fetch=”join” – Faça um join com o objeto principal e traga junto com ele. Essa opção ANULA a opção lazy = “true” EAGER, seria equivalente lazy = false.

  1. @Fetch( FetchMode.SELECT )
  2. @Fetch( FetchMode.JOIN )

Todos os relacionamentos *ToOne sãoEAGER, e os *ToMany são LAZY, isso porque relações *toMany são provavelmente mais custosas, trazendo mais objetos para a memória. Caelum

————————————————————————-
Problemas com lazy init (LazyInitializationException)?

Session session = sessionFactory.openSession();
NotaFiscal nf = (NotaFiscal) session.load(NotaFiscal.class, 42);
session.close();

List items = nf.getItems();
System.out.println("numero de pedidos dessa nota:" + items.size());

Esse código tem o seguinte resultado:

org.hibernate.LazyInitializationException: failed to lazily initialize a collection - no session or session was closed.

Utilize o open session in view: Sempre fechar a sessão ao término do trabalho. Mas e quando estamos trabalhando na Web? Após pegarmos os dados necessários no nosso controlador, fechamos a sessão e passamos os objetos ao JSP através de atributos. O JSP, ao acessar um getter do seu objeto para fazer um loop, como ${notaFiscal.items}, recebeLazyInitializationException da mesma forma. Em um primeiro momento o desenvolvedor muda o relacionamento para EAGER, mas isso gera uma enorme sobrecarga, pois provavelmente em muitos lugares não era necessário carregar todos os itens da compra sempre que uma determinada nota fiscal é requisitada. Como então evitar a LazyInitializationException sem modificar o relacionamento paraEAGER? Open Session In View A solução é manter a session aberta durante a renderização da camada de visualização, ou como o Hibernate chama esse pequeno padrão: open session in view. A idéia é bastante simples: a sessão deve ser mantida aberta até o fim da renderização do JSP (ou de qualquer outra camada de apresentação). Isso pode ser obtido através da implementação de um Servlet Filter, algum tipo de interceptador do seu framework preferido ou até mesmo aspectos. O Spring foi sem dúvida um dos primeiros frameworks a já trazer classes para isso embutidas (assim como também foi o primeiro a fazer o wrap da HibernateException dentro de uma exceçãounchecked, pois até o Hibernate 2.x essa exceção era checked). Há as classesOpenSessionInViewInterceptor e sua análoga OpenEntityManagerInViewInterceptor. No VRaptor, além de você pode usar os componentes embutidos do Spring, já existem componentes que fazem o mesmo trabalho (ver componentes embutidos). Leia a matéria completa no blog da CAELUM: http://blog.caelum.com.br/2009/10/13/enfrentando-a-lazyinitializationexception-no-hibernate/  Outro problema:

Hibernate – could not initialize proxy – no Session
  1. 09:15:11,883 ERROR LazyInitializationException:19 – could not initialize proxy – no Session
  2. org.hibernate.LazyInitializationException: could not initialize proxy – no Session
  3.     at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:57)
  4.     at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:111)
  5.     at org.hibernate.proxy.pojo.cglib.CGLIBLazyInitializer.invoke(CGLIBLazyInitializer.java:150)
  6.     at org.iprogramming.model.persistence.dto.Person$$EnhancerByCGLIB$$4dfa7473.getName(<generated>)

Essa exception ocorre porque voce fechou a sessão do hibernate (ou entitymanager do JPA usando hibernate). Provavelmente voces estao fechando a sessao/entityManager antes de renderizar a pagina, isso é, antes de fazer o dispatch!

————————————————————————-
Leia a discussão sobre este problema e outras soluções no GUJ:
http://www.guj.com.br/java/60474-hibernate—could-not-initialize-proxy—no-session
http://www.guj.com.br/java/23319-hibernate-3—-orghibernatelazyinitializationexception-could-not-initialize-proxy—the-owning-se

Fonte: Jardelmorais

Anúncios

Analisando Metadados com JDBC

Introdução

Neste Tutorial você aprenderá a recuperar metadados de seu banco de dados, tabelas e stored procedures. Mas, o que são metadados? Como o próprio nome diz, Metadados são informações sobre os seus dados. Pense em metadata como um reflection do seu banco de dados! Ex: Metadados de uma tabela são: nome das colunas, tipo de dados das colunas (VARCHAR, NUMBER), tamanho da coluna, proprietário da tabela,etc.

Motivação

Em algumas situações é necessário se recuperar esses metadados para construirmos nossas consultas dinamicamente, pois em uma grande base de dados algumas mudanças estruturais podem ocorrer com certa frequência. Alguns desenvolvedores constróem seus próprios frameworks utilizando as funcionalidades de recuperação de metadados do JDBC. Assim quando um Analista de Dados alterar o modelo relacional, acrescentando colunas ou alterando o tipo das mesmas, as suas aplicações não precisam sofrer manutenções. Existem três classes que nos permitem recuperar metadados a partir do Driver JDBC, no pacote java.sql:

  • DatabaseMetaData
  • ResultSetMetaData
  • ParameterMetaData (nova, JDBC 3.0)
    A Classe DatabaseMetaData

    A classe DatabaseMetaData é recuperada através do objeto Connection e nos permitirá recuperar metadados sobre o banco de dados em uso, objetos do banco de dados, informações sobre o Driver JDBC, privilégios de acesso, etc. Existem mais de 150 métodos disponíveis para esta classe. Vamos então verificar como utilizar a Classe DatabaseMetaData :

    1. package br.com.guj;
    2. import java.sql.*;
    3. public class Exemplo1 {
    4.     public static void main(String[] args) throws SQLException {
    5.         // registrar o Driver JDBC do banco de dados, neste caso estou usando o da Oracle
    6.         DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver());
    7.         // String de conexao para uma base Oracle
    8.         Connection conn = DriverManager.getConnection(“jdbc:oracle:thin:@127.0.0.1:1521:orcl”,”scott”,”tiger”);
    9.         // recuperar a classe  DatabaseMetadaData a partir da conexao criada
    10.         DatabaseMetaData dbmd = conn.getMetaData();
    11.         System.out.println ( “Versao do Driver JDBC = “+ dbmd.getDriverVersion());
    12.         System.out.println ( “Versao do Banco de Dados = “+ dbmd.getDatabaseProductVersion());
    13.         System.out.println ( “Suporta Select for Update? = “+ dbmd.supportsSelectForUpdate());
    14.         System.out.println ( “Suporta Transacoes? = “+ dbmd.supportsTransactions());
    15.         // retornar todos os schemas(usuarios) do Banco de Dados
    16.         ResultSet r2 = dbmd.getSchemas();
    17.         while (r2.next()) {
    18.             System.out.println(“SCHEMA DO BD = ” + r2.getString(1));
    19.         }
    20.     }
    21. }
    A Classe ResultSetMetaData

    A outra Classe que pode ser utilizada para recuperar mais metadados é a ResultSetMetaData, com um objeto dessa classe você poderá dinamicamente recuperar a quantidade de colunas de uma tabela (não estou me referindo a registros ou linhas, e sim colunas), também poderá dinamicamente descobrir o nome da coluna, seu tipo, tamanho, entre outras informações. Neste próximo exemplo iremos utilizar a classe ResultSetMetaData para descobrirmos dinamicamente o total de colunas de uma tabela, o nome de suas colunas e o tipo das mesmas.

    1.   …
    2. Statement stmt = conn.createStatement();
    3. // Tabela a ser analisada
    4. ResultSet rset = stmt.executeQuery(“SELECT * from EMP “);
    5. ResultSetMetaData rsmd = rset.getMetaData();
    6. // retorna o numero total de colunas
    7. int numColumns = rsmd.getColumnCount();
    8. System.out.println(“Total de Colunas = ” + numColumns);
    9. // loop para recuperar os metadados de cada coluna
    10. for (int i=0; i<numColumns; i++) {
    11.     System.out.print(“Nome da Coluna=” + rsmd.getColumnName (i + 1));
    12.     System.out.print(” Tipo=” + rsmd.getColumnType (i + 1) );
    13.     System.out.print(” Nome do Tipo=” + rsmd.getColumnTypeName (i + 1));
    14.     System.out.print(” Tamanho=” + rsmd.getColumnDisplaySize (i + 1));
    15.     System.out.println(” Casas Decimais=” + rsmd.getScale(i + 1));
    16. }

    Você ainda pode utilizar as classes PreparedStatement ou CallableStatement para uma instância ResultSetMetaData. Comprove no exemplo abaixo:

    1. PreparedStatement ps = conn.prepareStatement(“SELECT * FROM EMP where EMPNO = ? “);
    2. ps.setLong(1,1020L);
    3. ResultSetMetaData rsmd = ps.getMetaData();
    4. // retorna o numero total de colunas
    5. int numColumns = rsmd.getColumnCount();
    6. System.out.println(“Total de Colunas = ” + numColumns);
    A Classe ParameterMetaData

    Através da classe ParameterMetaData é possível recuperar metadados sobre os “parâmetros” de cláusulas SQL que usamos com a classe PreparedStatement. Assim poderemos descobrir dinamicamente a quantidade de parâmetros utilizados e suas características. Confiram no exemplo abaixo o uso da classe ParameterMetaData recuperando informações sobres os parâmetros “?” da clásula SQL.

    1. PreparedStatement pstmt = conn.prepareStatement(“SELECT * FROM EMP WHERE EMPNO = ? AND DEPTNO = ?”);
    2. ParameterMetaData pmd = pstmt.getParameterMetaData();
    3. // recupera o total de parametros
    4. int totalParam = pmd.getParameterCount();
    5. // recupera informacoes sobre cada parametro
    6. for (int i=0; i < totalParam; i++) {
    7.     int tipoParam = pmd.getParameterType(i+1);
    8.     String nomeTipoParam = pmd.getParameterTypeName(i+1);
    9. }
    Resumo e conclusão

    Um objeto DatabaseMetaData é obtida através do objeto Connection e oferecerá recursos de recuperação de metadados da base de dados e da sua conexão atual, pode ser utilizada por exemplo para verificar quais os schemas(usuários) de uma base de dados, se a conexão atual possui suporte a um determinado nível de isolamente de transações, ou até mesmo qual a versão do Driver JDBC. Um objeto ResultSetMetaData pode ser obtida através de um ResultSet previamente criado ou através das classes PreparedStatement e CallableStatement, lhe possibilitando a recuperação de metadados sobre as colunas da cláusula SQL atual, como a quantidade de colunas, nome e tipos das mesmas. Um objeto ParameterMetaData é obtida através de um PreparedStatement, e permite que você possa recuperar metadados sobre os parâmetros usados em clausulas SQL. Com essas três classes é possível recuperar informações dinamicamente de uma base de dados. Alguns desenvolvedores utilizam constantemente essas três classes para criarem seu próprio framework de persistência de dados.

Fonte: GUJ – Adriano Marcandali