SlideShare una empresa de Scribd logo
1 de 163
Descargar para leer sin conexión
Hibernate EFETIVO
                          ERROS COMUNS E SOLUÇÕES




Tuesday, August 7, 2012
Eu estava me
  perguntando quando de
  fato o Hibernate foi
  criado...



Tuesday, August 7, 2012
Eu estava me
  perguntando quando de
  fato o Hibernate foi
  criado...
                          O “Boom” foi em 2003!




      Luca Bastos
Tuesday, August 7, 2012
Quase uma década!
                             2012 - 2003 = 9




Tuesday, August 7, 2012
mas ainda hoje...




Tuesday, August 7, 2012
mas ainda hoje...
  existem devs que
  subutilizam o framework




Tuesday, August 7, 2012
mas ainda hoje...
  existem devs que
  subutilizam o framework

          problemas de perfomance
               e escalabilidade
Tuesday, August 7, 2012
e pra piorar...



Tuesday, August 7, 2012
culpam o Hibernate




Tuesday, August 7, 2012
culpam o Hibernate

                          A culpa é do Banco de
                                 Dados!


          Sérgio




Tuesday, August 7, 2012
é fácil culpar o que não se
  conhece...




Tuesday, August 7, 2012
um SGDB mal configurado
                           pode ser o problema...




Tuesday, August 7, 2012
um SGDB mal configurado
                           pode ser o problema...




                             MAS na maioria das vezes o
                                problema está na SUA
                                   APLICAÇÃO
Tuesday, August 7, 2012
tabelas sem índices




                                        <3
Tuesday, August 7, 2012
tabelas sem índices
                            consultas mal-feitas




                                        <3 <3
Tuesday, August 7, 2012
tabelas sem índices
                            consultas mal-feitas
  muitos hits ao banco




Tuesday, August 7, 2012
                                        <3 <3      <3
tabelas sem índices
                               consultas mal-feitas
  muitos hits ao banco
                          connection leaks




Tuesday, August 7, 2012
                                             <3 <3    <3
tabelas sem índices
                                 consultas mal-feitas
  muitos hits ao banco
                            connection leaks
                          memory leaks


Tuesday, August 7, 2012
                                               <3 <3    <3
Não saber tirar
                          proveito framework



Tuesday, August 7, 2012
Hibernate Efetivo
                           6 dicas para não deixar
                               sua app morrer



Tuesday, August 7, 2012
@rponte




Tuesday, August 7, 2012
Tuesday, August 7, 2012
Fortaleza - Terra do Sol
Tuesday, August 7, 2012
#1
                           POOL DE
                          CONEXÕES

Tuesday, August 7, 2012
com certeza todos aqui
                    já ouviram falar...


Tuesday, August 7, 2012
mas nem todos dão a devida atenção...




Tuesday, August 7, 2012
mas nem todos dão a devida atenção...
              até perceberem a app engasgando




Tuesday, August 7, 2012
mas nem todos dão a devida atenção...
              até perceberem a app engasgando
      ou até receberem um




Tuesday, August 7, 2012
mas nem todos dão a devida atenção...
              até perceberem a app engasgando
      ou até receberem um

         org.hibernate.exception.Gener
           icJDBCException: Cannot
                open connection



Tuesday, August 7, 2012
daí percebem que não configuraram o
                               o pool do Hibernate

                                         hibernate.properties
  hibernate.connection.driver_class=org.postgresql.Driver
  hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect
  hibernate.connection.url=jdbc:postgresql://localhost:5432/myapp
  hibernate.connection.username=postgres
  hibernate.connection.password=1234




Tuesday, August 7, 2012
daí percebem que não configuraram o
                               o pool do Hibernate

                                         hibernate.properties
  hibernate.connection.driver_class=org.postgresql.Driver
  hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect
  hibernate.connection.url=jdbc:postgresql://localhost:5432/myapp
  hibernate.connection.username=postgres
  hibernate.connection.password=1234
  hibernate.connection.pool_size=30




Tuesday, August 7, 2012
daí percebem que não configuraram o
                               o pool do Hibernate

                                         hibernate.properties
  hibernate.connection.driver_class=org.postgresql.Driver
  hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect
  hibernate.connection.url=jdbc:postgresql://localhost:5432/myapp
  hibernate.connection.username=postgres
  hibernate.connection.password=1234
  hibernate.connection.pool_size=30




Tuesday, August 7, 2012
a app volta a funcionar
                      bem por um tempo


Tuesday, August 7, 2012
a app volta a funcionar
                      bem por um tempo


Tuesday, August 7, 2012
e vão alocando mais conexões com o
                                         tempo

                                                                                 hibernate.properties

  hibernate.connection.pool_size=30
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  40
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  55
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  70
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  ...




Tuesday, August 7, 2012
o pool PADRÃO do
                          Hibernate



Tuesday, August 7, 2012
que possui uma impl.
                            RUDIMENTAR


Tuesday, August 7, 2012
INFO DriverManagerConnectionProvider:64 - Using Hibernate built-in
  connection pool (not for production use!)
  INFO DriverManagerConnectionProvider:65 - Hibernate connection pool
  size: 20




Tuesday, August 7, 2012
not for production use!

  INFO DriverManagerConnectionProvider:64 - Using Hibernate built-in
  connection pool (not for production use!)
  INFO DriverManagerConnectionProvider:65 - Hibernate connection pool
  size: 20




Tuesday, August 7, 2012
qual pool utilizar?



Tuesday, August 7, 2012
temos ótimas opções...




Tuesday, August 7, 2012
temos ótimas opções...




                          pools como c3p0 ou
                           commons-dbcp
Tuesday, August 7, 2012
o Hibernate já vem
                              com c3p0



Tuesday, August 7, 2012
configurando c3p0


                                     hibernate.properties
  hibernate.connection.driver_class=org.postgresql.Driver
  hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect
  hibernate.connection.url=jdbc:postgresql://localhost:5432/myapp
  hibernate.connection.username=postgres
  hibernate.connection.password=1234
  hibernate.c3p0.min_size=5
  hibernate.c3p0.max_size=20
  hibernate.c3p0.timeout=1800
  hibernate.c3p0.max_statements=50




Tuesday, August 7, 2012
ou melhor ainda...



Tuesday, August 7, 2012
podemos obter as conexões de um DataSource

               <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
               destroy-method="close">
               ! <!-- access configuration -->
               ! <property name="driverClass" value="${jdbc.driverclass}" />
               ! <property name="jdbcUrl" value="${jdbc.url}" />
               ! <property name="user" value="${jdbc.username}" />
               ! <property name="password" value="${jdbc.password}" />
               ! <!-- pool sizing -->
               ! <property name="initialPoolSize" value="3" />
               ! <property name="minPoolSize" value="6" />
               ! <property name="maxPoolSize" value="25" />
               ! <property name="acquireIncrement" value="3" />
               ! <property name="maxStatements" value="0" />
               ! <!-- retries -->
               ! <property name="acquireRetryAttempts" value="30" />
               ! <property name="acquireRetryDelay" value="1000" /> <!-- 1s -->
               ! <property name="breakAfterAcquireFailure" value="false" />
               ! <!-- refreshing connections -->
               ! <property name="maxIdleTime" value="180" /> <!-- 3min -->
               ! <property name="maxConnectionAge" value="10" /> <!-- 1h -->
               ! <!-- timeouts e testing -->
               ! <property name="checkoutTimeout" value="5000" /> <!-- 5s -->
               ! <property name="idleConnectionTestPeriod" value="60" /> <!-- 60 -->
               ! <property name="testConnectionOnCheckout" value="true" />
               ! <property name="preferredTestQuery" value="SELECT 1+1" />
               </bean>


Tuesday, August 7, 2012
Pool traz melhoria de
                              performance




Tuesday, August 7, 2012
Pool traz melhoria de
                              performance
                  mas não faz milagres


Tuesday, August 7, 2012
#2
                              lidando com
                          LazyInitialization
                             Exception

Tuesday, August 7, 2012
quando e por que acontece?




Tuesday, August 7, 2012
@Entity
                          class	
  NotaFiscal	
  {
                          	
  	
  …
                          	
  	
  @OneToMany
                          	
  	
  List<Item>	
  itens;
                          }




Tuesday, August 7, 2012
Percorrendo os itens de uma nota




               NotaFiscal	
  nf	
  =	
  (NotaFiscal)	
  session.load
               (NotaFiscal.class,	
  42);
               List<Item>	
  itens	
  =	
  nf.getItens();




Tuesday, August 7, 2012
Hibernate executa 2 selects



    NotaFiscal	
  nf	
  =	
  (NotaFiscal)	
  session.load(NotaFiscal.class,	
  42);


                select nf.* from NotaFiscal nf
               where nf.id=42
    List<Item>	
  itens	
  =	
  nf.getItens();


                 select i.* from Item i
                where i.nota_fiscal_id=42



Tuesday, August 7, 2012
a session do Hibernate foi fechada

               Session	
  session	
  =	
  
               sessionFactory.openSession();

               NotaFiscal	
  nf	
  =	
  (NotaFiscal)	
  session.load
               (NotaFiscal.class,	
  42);

               session.close();

               List<Item>	
  itens	
  =	
  nf.getItens();
               System.out.println("numero	
  de	
  pedidos:"	
  +	
  
               itens.size());




Tuesday, August 7, 2012
mas ao ler os itens da nota

               Session	
  session	
  =	
  
               sessionFactory.openSession();

               NotaFiscal	
  nf	
  =	
  (NotaFiscal)	
  session.load
                org.hibernate.LazyInitializationException:
               (NotaFiscal.class,	
  42);
                   failed to lazily
               session.close();       initialize a collection -
                          no session or session was closed.
               List<Item>	
  itens	
  =	
  nf.getItens();
               System.out.println("numero	
  de	
  pedidos:"	
  +	
  
               itens.size());




Tuesday, August 7, 2012
resolver parece fácil, certo?




Tuesday, August 7, 2012
fechar a session ao término do trabalho

               Session	
  session	
  =	
  
               sessionFactory.openSession();

               NotaFiscal	
  nf	
  =	
  (NotaFiscal)	
  session.load
               (NotaFiscal.class,	
  42);

               List<Item>	
  itens	
  =	
  nf.getItens();
               System.out.println("numero	
  de	
  pedidos:"	
  +	
  
               itens.size());

               session.close();




Tuesday, August 7, 2012
Mas e quando estamos
                           trabalhando na Web?




Tuesday, August 7, 2012
NotaFiscalController.java
         @Get("/notas/{id}")
         public	
  void	
  view(Long	
  id)	
  {
         	
  	
  NotaFiscal	
  nf	
  =	
  notaFiscalDao.carrega(id);
         	
  	
  result.include("nf",	
  nf);
         	
  	
  result.forwardTo("/notas/view.jsp");
         }


    view.jsp
         <c:forEach	
  var="item"	
  items="${nf.itens}">
         	
  	
  	
  	
  ${item.produto.descricao}<br/>
         </c:forEach>



Tuesday, August 7, 2012
NotaFiscalController.java
         @Get("/notas/{id}")
         public	
  void	
  view(Long	
  id)	
  {
         	
  	
  NotaFiscal	
  nf	
  =	
  notaFiscalDao.carrega(id);
         	
  	
  result.include("nf",	
  nf);
         	
  	
  result.forwardTo("/notas/view.jsp");
         }
                          LazyInitializationException
    view.jsp
         <c:forEach	
  var="item"	
  items="${nf.itens}">
         	
  	
  	
  	
  ${item.produto.descricao}<br/>
         </c:forEach>



Tuesday, August 7, 2012
e agora? #comofas




Tuesday, August 7, 2012
e agora? #comofas

                                passa tudo pra
                                  EAGER! ;D


            Sérgio


Tuesday, August 7, 2012
@Entity
     class	
  NotaFiscal	
  {
     	
  	
  …
     	
  	
  @OneToMany(fetch=FetchType.EAGER)
     	
  	
  List<Item>	
  itens;
     }




Tuesday, August 7, 2012
Hibernate executa 1 select



 NotaFiscal	
  nf	
  =	
  (NotaFiscal)	
  session.load(NotaFiscal.class,	
  42);



      select nf.*, i.* from NotaFiscal
     nf left outer join Item i on
     nf.id = i.nota_fiscal_id
     where nf.id=42




Tuesday, August 7, 2012
mas isso poderia gerar
  uma sobrecarga...




Tuesday, August 7, 2012
mas isso poderia gerar
  uma sobrecarga...



                           pois os itens da nota
                          não são necessários em
                              muitos lugares
Tuesday, August 7, 2012
lembre-se que ter os
        relacionamentos como LAZY é
                uma boa prática



Tuesday, August 7, 2012
como evitar LIE sem
                          modificar o relacionamento
                                       para EAGER?




Tuesday, August 7, 2012
Open Session In
                       View


Tuesday, August 7, 2012
Servlet Filter
     @WebFilter(urlPatterns="/*")
     public	
  class	
  OpenSessionInViewFilter	
  implements	
  Filter	
  {

     	
   SessionFactory	
  sessionFactory;
     	
  
     	
   @Override
     	
   public	
  void	
  doFilter(ServletRequest	
  req,	
  ServletResponse	
  res,	
  
     FilterChain	
  chain)	
  {
                	
   Transaction	
  transaction	
  =	
  null;
     	
  	
  	
  	
  	
  	
  	
  try	
  {
     	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  Session	
  session	
  =	
  sessionFactory.getCurrentSession();
                	
  	
  	
  	
  	
  	
  	
  transaction	
  =	
  session.beginTransaction();
     	
  	
  	
  	
  	
  	
  	
  	
  	
  
                	
  	
  	
  	
  	
  	
  	
  chain.doFilter(req,	
  res);
     	
  	
  	
  	
  	
  	
  	
  	
  	
  
                	
  	
  	
  	
  	
  	
  	
  transaction.commit();
     	
   	
   }	
  finally	
  {
     	
   	
   	
   if	
  (transaction	
  !=	
  null	
  &&	
  transaction.isActive())	
  {
     	
   	
   	
   	
   transaction.rollback();
     	
   	
   	
   }
     	
   	
   }
     	
   }
     }
Tuesday, August 7, 2012
o OSIV só evita LIE no
                       mesmo request!


Tuesday, August 7, 2012
anti-pattern?



Tuesday, August 7, 2012
#3
                          Second Level
                             Cache

Tuesday, August 7, 2012
Carregando uma nota por ID




               NotaFiscal	
  nf	
  =	
  (NotaFiscal)	
  session.load
               (NotaFiscal.class,	
  42);




Tuesday, August 7, 2012
Session




                          Banco de Dados



Tuesday, August 7, 2012
First Level Cache

                             Session




                          Banco de Dados



Tuesday, August 7, 2012
Session   Session   Session   Session




                                     Banco de Dados



Tuesday, August 7, 2012
Session   Session    Session   Session


                                    Second Level Cache



                                     Banco de Dados



Tuesday, August 7, 2012
First Level Cache

                          Session   Session    Session      Session


                                    Second Level Cache



                                     Banco de Dados



Tuesday, August 7, 2012
Session   Session    Session   Session


                                      SessionFactory



                                     Banco de Dados



Tuesday, August 7, 2012
Configurar é simples



Tuesday, August 7, 2012
#1 configuramos o Hibernate


                                          hibernate.properties
  hibernate.cache.use_second_level_cache=true
  hibernate.cache.region.factory_class=net.sf.ehcac
  he.hibernate.EhCacheRegionFactory




Tuesday, August 7, 2012
#2 configuramos as entidades


   @Entity
   @Cache(usage=CacheConcurrencyStrategy.READ_WRITE)
   class	
  Issue	
  {
          @Id
   	
  	
  private	
  Long	
  id;
          private	
  String	
  descricao;
          private	
  String	
  status;
          @ManyToOne
          private	
  Projeto	
  projeto;
   	
  	
  @OneToMany
   	
  	
  private	
  List<Comentario>	
  comentarios;
   }

Tuesday, August 7, 2012
Caching Strategy


   @Cache(
     usage=CacheConcurrencyStrategy.READ_WRITE)



           READ_ONLY


      NONSTRICT_READ_WRITE


          READ_WRITE


Tuesday, August 7, 2012
Caching Strategy


   @Cache(
     usage=CacheConcurrencyStrategy.READ_WRITE)



           READ_ONLY          Melhor performance

      NONSTRICT_READ_WRITE


          READ_WRITE


Tuesday, August 7, 2012
Caching Strategy


   @Cache(
     usage=CacheConcurrencyStrategy.READ_WRITE)



           READ_ONLY


      NONSTRICT_READ_WRITE        Dados não críticos

          READ_WRITE


Tuesday, August 7, 2012
Caching Strategy


   @Cache(
     usage=CacheConcurrencyStrategy.READ_WRITE)



           READ_ONLY


      NONSTRICT_READ_WRITE


          READ_WRITE      Modificações frequentes


Tuesday, August 7, 2012
ehcache.xml
                 <cache
                 	
  	
  	
  	
  name="br.com.triadworks.model.Issue"
                 	
  	
  	
  	
  maxElementsInMemory="10000"
                 	
  	
  	
  	
  eternal="false"
                 	
  	
  	
  	
  timeToIdleSeconds="1800"
                 	
  	
  	
  	
  timeToLiveSeconds="10000"
                 	
  	
  	
  	
  overflowToDisk="true"
                 	
  	
  	
  	
  memoryStoreEvictionPolicy="LRU"
                 />



Tuesday, August 7, 2012
Como 2nd Level Cache
                      funciona?


Tuesday, August 7, 2012
2nd Level Cache não faz cache
                   das instancias das entidades




Tuesday, August 7, 2012
2nd Level Cache não faz cache
                   das instancias das entidades
                 somente dos valores
                   das propriedades

Tuesday, August 7, 2012
@Entity
   @Cache(usage=CacheConcurrencyStrategy.READ_WRITE)
   class	
  Issue	
  {
          @Id
   	
  	
  private	
  Long	
  id;
          private	
  String	
  descricao;
          private	
  String	
  status;
          @ManyToOne
          private	
  Projeto	
  projeto;
   	
  	
  @OneToMany
   	
  	
  private	
  List<Comentario>	
  comentarios;
   }

Tuesday, August 7, 2012
modelo conceitual do cache


                          Issue Data Cache
        17 -> [ “Bug #1”, “ABERTA” , 1 ]
        18 -> [ “Bug #2”, “FECHADA”, 2 ]
        19 -> [ “Bug #3”, “ABERTA” , 1 ]




Tuesday, August 7, 2012
modelo conceitual do cache


                            Issue Data Cache
        17 -> [ “Bug #1”, “ABERTA” , 1 ]
        18 -> [ “Bug #2”, “FECHADA”, 2 ]
        19 -> [ “Bug #3”, “ABERTA” , 1 ]



                     não é uma árvore de objetos,
                     mas sim um "Map de Arrays"

Tuesday, August 7, 2012
2nd Level Cache não faz cache
                         das associações




Tuesday, August 7, 2012
@Entity
   @Cache(usage=CacheConcurrencyStrategy.READ_WRITE)
   class	
  Issue	
  {
          @Id
   	
  	
  private	
  Long	
  id;
          private	
  String	
  descricao;
          private	
  String	
  status;
          @ManyToOne
          private	
  Projeto	
  projeto;
   	
  	
  @OneToMany
   	
  	
  @Cache(usage=CacheConcurrencyStrategy.READ_WRITE)
   	
  	
  private	
  List<Comentario>	
  comentarios;
   }

Tuesday, August 7, 2012
modelo conceitual do cache


                          Issue Data Cache
        17 -> [ “Bug #1”, “ABERTA” , 1, [1,2] ]
        18 -> [ “Bug #2”, “FECHADA”, 2, [] ]
        19 -> [ “Bug #3”, “ABERTA” , 1, [3] ]




Tuesday, August 7, 2012
Devo cachear todas as
                     minhas entidades?


Tuesday, August 7, 2012
Com 2nd Level Cache tudo funciona bem
    enquanto buscamos por ID...
                  session.load(Issue.class,	
  17);




Tuesday, August 7, 2012
Com 2nd Level Cache tudo funciona bem
    enquanto buscamos por ID...
                  session.load(Issue.class,	
  17);


                             ...mas e quando precisamos de uma
                                   consulta um pouco diferente?
   session
   	
  	
  .createQuery("from	
  Issue	
  where	
  status	
  =	
  ?")
   	
  	
  .setString(0,"ABERTO")
   	
  	
  .list();	
  



Tuesday, August 7, 2012
#4
                          Query Cache


Tuesday, August 7, 2012
Query Cache faz cache do
                           resultado de uma query




Tuesday, August 7, 2012
Configurando Hibernate para
                          usar Query Cache

                                          hibernate.properties
  hibernate.cache.use_query_cache=true




Tuesday, August 7, 2012
Query Cache



   session
   	
  	
  .createQuery("from	
  Issue	
  where	
  status	
  =	
  ?")
   	
  	
  .setString(0,	
  status)
   	
  	
  .setCacheable(true)
   	
  	
  .list();	
  




Tuesday, August 7, 2012
modelo conceitual do query cache


                          Query Cache


 [“from Issue where status = ?”, [“ABERTA”]] -> [17, 19]




Tuesday, August 7, 2012
modelo conceitual do query cache


                                    Query Cache


 [“from Issue where status = ?”, [“ABERTA”]] -> [17, 19]



                          Query + Parâmetros                      IDs




Tuesday, August 7, 2012
por isso Query Cache SEM
                           2nd Level Cache não é de
                                  muita ajuda



Tuesday, August 7, 2012
Utilize somente em consultas
                     que são executadas repetidas
                      vezes com os mesmos
                             parâmetros



Tuesday, August 7, 2012
Utilize somente em consultas
                     que são executadas repetidas
                      vezes com os mesmos
                             parâmetros



Tuesday, August 7, 2012
#5
                          Select n+1


Tuesday, August 7, 2012
o campeão em prejudicar
                              a performance da
                                  aplicação




Tuesday, August 7, 2012
Processando os itens de uma nota




               NotaFiscal	
  nf	
  =	
  (NotaFiscal)	
  session.load
               (NotaFiscal.class,	
  42);
               processaItensDaNota(nf);




Tuesday, August 7, 2012
Hibernate executa 2 selects



    NotaFiscal	
  nf	
  =	
  (NotaFiscal)	
  session.load(NotaFiscal.class,	
  42);


                select nf.* from NotaFiscal nf
               where nf.id=42
    processaItensDaNota(nf);


                 select i.* from Item i
                where i.nota_fiscal_id=42



Tuesday, August 7, 2012
Processando os itens de varias notas




               List<NotaFiscal>	
  notas	
  =	
  dao.listaTudo();
               for	
  (NotaFiscal	
  nf	
  :	
  notas)	
  {
               	
  	
  	
  	
  processaItensDaNota(nf);
               }




Tuesday, August 7, 2012
Hibernate executa n+1 selects

    List<NotaFiscal>	
  notas	
  =	
  dao.listaTudo();


                   select nf.* from NotaFiscal nf

    for	
  (NotaFiscal	
  nf	
  :	
  notas)	
  {
    	
  	
  	
  	
  processaItensDaNota(nf);
    }

                   select           i.*        from   Item   i   where   i.nota_fiscal_id=?
                   select           i.*        from   Item   i   where   i.nota_fiscal_id=?
                   select           i.*        from   Item   i   where   i.nota_fiscal_id=?
                   select           i.*        from   Item   i   where   i.nota_fiscal_id=?
                   select           i.*        from   Item   i   where   i.nota_fiscal_id=?
                   ...



Tuesday, August 7, 2012
são muitos hits no banco de
  dados




Tuesday, August 7, 2012
são muitos hits no banco de
  dados
                          mas podemos resolver
                                         isso...




Tuesday, August 7, 2012
3 soluções



Tuesday, August 7, 2012
#1 EAGER ou join-
                               fetch


Tuesday, August 7, 2012
Utilizando FetchMode=EAGER



     @Entity
     class	
  NotaFiscal	
  {
     	
  	
  …
     	
  	
  @OneToMany(fetch=FetchType.EAGER)
     	
  	
  List<Item>	
  itens;
     }




Tuesday, August 7, 2012
Hibernate executa 1 select



  List<NotaFiscal>	
  notas	
  =	
  dao.listaTudo();




      select nf.*, i.* from NotaFiscal
     nf left outer join Item i on
     nf.id = i.nota_fiscal_id




Tuesday, August 7, 2012
antes de definir um
                          mapeamento global deste
                              tipo você precisa se
                                       perguntar...
Tuesday, August 7, 2012
SEMPRE que uma nota é
                           necessária, todos seus
                             itens também são
                                necessários?



Tuesday, August 7, 2012
não?
Tuesday, August 7, 2012
Utilizando Join Fetch



   session
   	
  	
  .createQuery("from	
  NotaFiscal	
  n	
  
   left	
  join	
  fetch	
  n.itens")
   	
  	
  .list();	
  




Tuesday, August 7, 2012
#2 batch-size nas
                            associações


Tuesday, August 7, 2012
É o meio termo entre
                             EAGER e LAZY




Tuesday, August 7, 2012
@BatchSize


     @Entity
     class	
  NotaFiscal	
  {
     	
  	
  …
     	
  	
  @OneToMany
     	
  	
  @BatchSize(size=10)
     	
  	
  List<Item>	
  itens;
     }



Tuesday, August 7, 2012
Hibernate executa n/10+1 selects

    List<NotaFiscal>	
  notas	
  =	
  dao.listaTudo();


                   select nf.* from NotaFiscal nf

    for	
  (NotaFiscal	
  nf	
  :	
  notas)	
  {
    	
  	
  	
  	
  processaItensDaNota(nf);
    }


                 select i.* from Item i where i.nota_fiscal_id
                in (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
                 select i.* from Item i where i.nota_fiscal_id
                in (?, ?, ?, ?, ?)




Tuesday, August 7, 2012
@BatchSize também é
  conhecido como:




Tuesday, August 7, 2012
@BatchSize também é
  conhecido como:

           otimização de adivinhação cega
                          (blind-guess optimization)




Tuesday, August 7, 2012
@BatchSize também é
  conhecido como:

           otimização de adivinhação cega
                          (blind-guess optimization)



                                  ou seja, é um palpite
Tuesday, August 7, 2012
#3 FetchMode
                           SUBSELECT


Tuesday, August 7, 2012
SUBSELECT


     @Entity
     class	
  NotaFiscal	
  {
     	
  	
  …
     	
  	
  @OneToMany
     	
  	
  @Fetch(FetchMode.SUBSELECT)
     	
  	
  List<Item>	
  itens;
     }



Tuesday, August 7, 2012
Hibernate executa 2 selects

    List<NotaFiscal>	
  notas	
  =	
  dao.listaTudo();


                   select nf.* from NotaFiscal nf

    for	
  (NotaFiscal	
  nf	
  :	
  notas)	
  {
    	
  	
  	
  	
  processaItensDaNota(nf);
    }


                 select i.* from Item i where
                i.nota_fiscal_id in (select nf.id from
                NotaFiscal nf)




Tuesday, August 7, 2012
Qual utilizar?



Tuesday, August 7, 2012
Qual utilizar?

                          depende
Tuesday, August 7, 2012
#6
                          Processamento
                             em lote

Tuesday, August 7, 2012
Imagine que temos que
                     importar 100k produtos para
                          o banco de dados




Tuesday, August 7, 2012
Session	
  session	
  =	
  sf.openSession();
     Transaction	
  tx	
  =	
  session.beginTransaction();
     	
   	
  
     for	
  (	
  int	
  i=0;	
  i	
  <	
  100000;	
  i++	
  )	
  {
     	
   Produto	
  produto	
  =	
  new	
  Produto(...);
     	
   session.save(produto);
     }
     	
   	
  
     tx.commit();
     session.close();




Tuesday, August 7, 2012
em ~50k produtos nós
                             receberíamos um
                          OutOfMemoryException




Tuesday, August 7, 2012
por que?




Tuesday, August 7, 2012
Hibernate faz cache de todas
                       as instâncias dos Produtos
                           inseridos na Session




Tuesday, August 7, 2012
mas como melhorar?




Tuesday, August 7, 2012
Session	
  session	
  =	
  sf.openSession();
     Transaction	
  tx	
  =	
  session.beginTransaction();
     	
   	
  
     for	
  (	
  int	
  i=0;	
  i	
  <	
  100000;	
  i++	
  )	
  {
     	
   Produto	
  produto	
  =	
  new	
  Produto(...);
     	
   session.save(produto);
     	
  	
  if	
  (i	
  %	
  100	
  ==	
  0)	
  {
     	
  	
  	
  	
  session.flush();
     	
  	
  	
  	
  session.clear();
     	
  	
  }
     }
     	
   	
  
     tx.commit();
     session.close();


Tuesday, August 7, 2012
evitamos o OutOfMemoryException




Tuesday, August 7, 2012
evitamos o OutOfMemoryException


                          Mas o processamento ainda
                                     continua lento!




Tuesday, August 7, 2012
evitamos o OutOfMemoryException


                          Mas o processamento ainda
                                     continua lento!


     Dá pra melhorar?

Tuesday, August 7, 2012
JDBC puro?



Tuesday, August 7, 2012
JDBC puro?

                             código de maxu!


   Handerson Frota
Tuesday, August 7, 2012
StatelessSession


Tuesday, August 7, 2012
API mais baixo nível

                                                         próxima ao jdbc
                          sem 1st Level Cache


       mapeamento básico                                sem 2nd Level Cache

                            StatelessSession
                                                                  sem cascade
     sem dirty-checking
                                                Collections são ignorados

                    sem modelo de
                                                             sem interceptors
                       eventos
Tuesday, August 7, 2012
StatelessSession	
  session	
  =	
  
     sf.openStatelessSession();
     Transaction	
  tx	
  =	
  session.beginTransaction();
     	
   	
  
     for	
  (	
  int	
  i=0;	
  i	
  <	
  100000;	
  i++	
  )	
  {
     	
   Produto	
  produto	
  =	
  new	
  Produto(...);
     	
   session.insert(produto);
     }
     	
   	
  
     tx.commit();
     session.close();



Tuesday, August 7, 2012
menos consumo de memória
              e mais rápida!



Tuesday, August 7, 2012
dá pra melhorar?



                                             Yuri Adams



        menos consumo de memória
              e mais rápida!



Tuesday, August 7, 2012
hibernate.properties

  hibernate.jdbc.batch_size=50




Tuesday, August 7, 2012
CONCLUSÃO


Tuesday, August 7, 2012
Foi apenas a ponta o iceberg!




Tuesday, August 7, 2012
cada uma destas dicas são simples,
             mas requerem mais estudo




Tuesday, August 7, 2012
cada uma destas dicas são simples,
             mas requerem mais estudo
              pois depende do projeto


Tuesday, August 7, 2012
um DBA certamente pode ter
                    ajudar em muitos cenários




Tuesday, August 7, 2012
Hibernate não é seu inimigo,
                              deixem de #mimimi




Tuesday, August 7, 2012
Rafael Ponte
                          rponte@triadworks.com.br




Tuesday, August 7, 2012

Más contenido relacionado

Destacado

自動応答Agent開発の取組み
自動応答Agent開発の取組み自動応答Agent開発の取組み
自動応答Agent開発の取組みtoshikazu fukami
 
Marketing y Posicionamiento de Marca Personal - Cristina Quiñones en el Foro ...
Marketing y Posicionamiento de Marca Personal - Cristina Quiñones en el Foro ...Marketing y Posicionamiento de Marca Personal - Cristina Quiñones en el Foro ...
Marketing y Posicionamiento de Marca Personal - Cristina Quiñones en el Foro ...Consumer Truth - Insights & Planning
 
R. Villano - Archivio Rotary International Distretto 2100-italia (p.te 3-4)
R. Villano - Archivio Rotary International Distretto 2100-italia (p.te 3-4)R. Villano - Archivio Rotary International Distretto 2100-italia (p.te 3-4)
R. Villano - Archivio Rotary International Distretto 2100-italia (p.te 3-4)Raimondo Villano
 
MongoDB 3.4: Deep Dive on Views, Zones, and MongoDB Compass
MongoDB 3.4: Deep Dive on Views, Zones, and MongoDB CompassMongoDB 3.4: Deep Dive on Views, Zones, and MongoDB Compass
MongoDB 3.4: Deep Dive on Views, Zones, and MongoDB CompassMongoDB
 
Deep phenotyping to aid identification of coding & non-coding rare disease v...
Deep phenotyping to aid identification  of coding & non-coding rare disease v...Deep phenotyping to aid identification  of coding & non-coding rare disease v...
Deep phenotyping to aid identification of coding & non-coding rare disease v...mhaendel
 
Taller de Desarrollo de Interfaces (UNSIJ 2017)
Taller de Desarrollo de Interfaces (UNSIJ 2017) Taller de Desarrollo de Interfaces (UNSIJ 2017)
Taller de Desarrollo de Interfaces (UNSIJ 2017) Mario A Moreno Rocha
 
Actores y público en el teatro griego
Actores y público en el teatro griegoActores y público en el teatro griego
Actores y público en el teatro griegoRosa Mariño
 
マイクロサービスバックエンドAPIのためのRESTとgRPC
マイクロサービスバックエンドAPIのためのRESTとgRPCマイクロサービスバックエンドAPIのためのRESTとgRPC
マイクロサービスバックエンドAPIのためのRESTとgRPCdisc99_
 
2016 SaaS Metrics Report
2016 SaaS Metrics Report2016 SaaS Metrics Report
2016 SaaS Metrics ReportTotango
 
Problems in team dynamics
Problems in team dynamics Problems in team dynamics
Problems in team dynamics Pramod Raghav
 
Rubricas de evaluación en el aula y CoRubrics
Rubricas de evaluación en el aula y CoRubricsRubricas de evaluación en el aula y CoRubrics
Rubricas de evaluación en el aula y CoRubricsRosa Liarte Alcaine
 
JSR 352 - Processamento Batch na Plataforma Java - JustJava 2013
JSR 352 - Processamento Batch na Plataforma Java - JustJava 2013JSR 352 - Processamento Batch na Plataforma Java - JustJava 2013
JSR 352 - Processamento Batch na Plataforma Java - JustJava 2013Danival Calegari
 
Importancia dos Testes Automatizados no dia a dia FIC-Estacio 2015
Importancia dos Testes Automatizados no dia a dia FIC-Estacio 2015Importancia dos Testes Automatizados no dia a dia FIC-Estacio 2015
Importancia dos Testes Automatizados no dia a dia FIC-Estacio 2015Rafael Ponte
 
Hibernate efetivo (COALTI-2014 / ALJUG)
Hibernate efetivo (COALTI-2014 / ALJUG)Hibernate efetivo (COALTI-2014 / ALJUG)
Hibernate efetivo (COALTI-2014 / ALJUG)Rafael Ponte
 
Migrations for Java (QCONSP2013)
Migrations for Java (QCONSP2013)Migrations for Java (QCONSP2013)
Migrations for Java (QCONSP2013)Rafael Ponte
 
Without warning: How everyday appliances become silent killers.
Without warning: How everyday appliances become silent killers.Without warning: How everyday appliances become silent killers.
Without warning: How everyday appliances become silent killers.The Law Buzz
 

Destacado (18)

自動応答Agent開発の取組み
自動応答Agent開発の取組み自動応答Agent開発の取組み
自動応答Agent開発の取組み
 
Marketing y Posicionamiento de Marca Personal - Cristina Quiñones en el Foro ...
Marketing y Posicionamiento de Marca Personal - Cristina Quiñones en el Foro ...Marketing y Posicionamiento de Marca Personal - Cristina Quiñones en el Foro ...
Marketing y Posicionamiento de Marca Personal - Cristina Quiñones en el Foro ...
 
R. Villano - Archivio Rotary International Distretto 2100-italia (p.te 3-4)
R. Villano - Archivio Rotary International Distretto 2100-italia (p.te 3-4)R. Villano - Archivio Rotary International Distretto 2100-italia (p.te 3-4)
R. Villano - Archivio Rotary International Distretto 2100-italia (p.te 3-4)
 
MongoDB 3.4: Deep Dive on Views, Zones, and MongoDB Compass
MongoDB 3.4: Deep Dive on Views, Zones, and MongoDB CompassMongoDB 3.4: Deep Dive on Views, Zones, and MongoDB Compass
MongoDB 3.4: Deep Dive on Views, Zones, and MongoDB Compass
 
Deep phenotyping to aid identification of coding & non-coding rare disease v...
Deep phenotyping to aid identification  of coding & non-coding rare disease v...Deep phenotyping to aid identification  of coding & non-coding rare disease v...
Deep phenotyping to aid identification of coding & non-coding rare disease v...
 
Taller de Desarrollo de Interfaces (UNSIJ 2017)
Taller de Desarrollo de Interfaces (UNSIJ 2017) Taller de Desarrollo de Interfaces (UNSIJ 2017)
Taller de Desarrollo de Interfaces (UNSIJ 2017)
 
Actores y público en el teatro griego
Actores y público en el teatro griegoActores y público en el teatro griego
Actores y público en el teatro griego
 
マイクロサービスバックエンドAPIのためのRESTとgRPC
マイクロサービスバックエンドAPIのためのRESTとgRPCマイクロサービスバックエンドAPIのためのRESTとgRPC
マイクロサービスバックエンドAPIのためのRESTとgRPC
 
2016 SaaS Metrics Report
2016 SaaS Metrics Report2016 SaaS Metrics Report
2016 SaaS Metrics Report
 
Problems in team dynamics
Problems in team dynamics Problems in team dynamics
Problems in team dynamics
 
Rubricas de evaluación en el aula y CoRubrics
Rubricas de evaluación en el aula y CoRubricsRubricas de evaluación en el aula y CoRubrics
Rubricas de evaluación en el aula y CoRubrics
 
ARDS ppt
ARDS pptARDS ppt
ARDS ppt
 
Hibernate reference pt-br
Hibernate reference pt-brHibernate reference pt-br
Hibernate reference pt-br
 
JSR 352 - Processamento Batch na Plataforma Java - JustJava 2013
JSR 352 - Processamento Batch na Plataforma Java - JustJava 2013JSR 352 - Processamento Batch na Plataforma Java - JustJava 2013
JSR 352 - Processamento Batch na Plataforma Java - JustJava 2013
 
Importancia dos Testes Automatizados no dia a dia FIC-Estacio 2015
Importancia dos Testes Automatizados no dia a dia FIC-Estacio 2015Importancia dos Testes Automatizados no dia a dia FIC-Estacio 2015
Importancia dos Testes Automatizados no dia a dia FIC-Estacio 2015
 
Hibernate efetivo (COALTI-2014 / ALJUG)
Hibernate efetivo (COALTI-2014 / ALJUG)Hibernate efetivo (COALTI-2014 / ALJUG)
Hibernate efetivo (COALTI-2014 / ALJUG)
 
Migrations for Java (QCONSP2013)
Migrations for Java (QCONSP2013)Migrations for Java (QCONSP2013)
Migrations for Java (QCONSP2013)
 
Without warning: How everyday appliances become silent killers.
Without warning: How everyday appliances become silent killers.Without warning: How everyday appliances become silent killers.
Without warning: How everyday appliances become silent killers.
 

Más de Rafael Ponte

TechDay: 10 Features do Oracle que voce nao conhecia - CONNECT BY CLAUSE
TechDay: 10 Features do Oracle que voce nao conhecia - CONNECT BY CLAUSETechDay: 10 Features do Oracle que voce nao conhecia - CONNECT BY CLAUSE
TechDay: 10 Features do Oracle que voce nao conhecia - CONNECT BY CLAUSERafael Ponte
 
TechDay Retrospectiva 2018
TechDay Retrospectiva 2018TechDay Retrospectiva 2018
TechDay Retrospectiva 2018Rafael Ponte
 
Arquitetura Java - Escalando além do Hype
Arquitetura Java - Escalando além do HypeArquitetura Java - Escalando além do Hype
Arquitetura Java - Escalando além do HypeRafael Ponte
 
Como treinar seu estagiario
Como treinar seu estagiarioComo treinar seu estagiario
Como treinar seu estagiarioRafael Ponte
 
Lidando com o Caos: Testando Código PLSQL em um Projeto Critico
Lidando com o Caos: Testando Código PLSQL em um Projeto CriticoLidando com o Caos: Testando Código PLSQL em um Projeto Critico
Lidando com o Caos: Testando Código PLSQL em um Projeto CriticoRafael Ponte
 
Como Apresentar Codigo em Slides - Javou #7 - 2016
Como Apresentar Codigo em Slides - Javou #7 - 2016Como Apresentar Codigo em Slides - Javou #7 - 2016
Como Apresentar Codigo em Slides - Javou #7 - 2016Rafael Ponte
 
Migrations for Java (Javou #4 - JavaCE)
Migrations for Java (Javou #4 - JavaCE)Migrations for Java (Javou #4 - JavaCE)
Migrations for Java (Javou #4 - JavaCE)Rafael Ponte
 
Hibernate efetivo (IA-2014 / Disturbing the Mind)
Hibernate efetivo (IA-2014 / Disturbing the Mind)Hibernate efetivo (IA-2014 / Disturbing the Mind)
Hibernate efetivo (IA-2014 / Disturbing the Mind)Rafael Ponte
 
Importancia dos Testes Automatizados no dia a dia (Don't Panic)
Importancia dos Testes Automatizados no dia a dia (Don't Panic)Importancia dos Testes Automatizados no dia a dia (Don't Panic)
Importancia dos Testes Automatizados no dia a dia (Don't Panic)Rafael Ponte
 
Importância dos testes automatizados no dia a dia
Importância dos testes automatizados no dia a diaImportância dos testes automatizados no dia a dia
Importância dos testes automatizados no dia a diaRafael Ponte
 
Migrations for Java
Migrations for JavaMigrations for Java
Migrations for JavaRafael Ponte
 
Os 10 maus habitos dos desenvolvedores jsf (JustJava e CCT)
Os 10 maus habitos dos desenvolvedores jsf (JustJava e CCT)Os 10 maus habitos dos desenvolvedores jsf (JustJava e CCT)
Os 10 maus habitos dos desenvolvedores jsf (JustJava e CCT)Rafael Ponte
 
Importância dos testes automatizadoss
Importância dos testes automatizadossImportância dos testes automatizadoss
Importância dos testes automatizadossRafael Ponte
 
Greenbar - Testes automatizados na sua empresa
Greenbar - Testes automatizados na sua empresaGreenbar - Testes automatizados na sua empresa
Greenbar - Testes automatizados na sua empresaRafael Ponte
 
Desafios de um desenvolvedor JSF
Desafios de um desenvolvedor JSFDesafios de um desenvolvedor JSF
Desafios de um desenvolvedor JSFRafael Ponte
 
Curso de Java server faces (JSF)
Curso de Java server faces (JSF)Curso de Java server faces (JSF)
Curso de Java server faces (JSF)Rafael Ponte
 
Os 10 maus hábitos dos desenvolvedores JSF
Os 10 maus hábitos dos desenvolvedores JSFOs 10 maus hábitos dos desenvolvedores JSF
Os 10 maus hábitos dos desenvolvedores JSFRafael Ponte
 
Boas Práticas com JavaServer Faces (Jsf)
Boas Práticas com JavaServer Faces (Jsf)Boas Práticas com JavaServer Faces (Jsf)
Boas Práticas com JavaServer Faces (Jsf)Rafael Ponte
 
JavaServer Faces - Desenvolvendo aplicações web com produtividade
JavaServer Faces - Desenvolvendo aplicações web com produtividadeJavaServer Faces - Desenvolvendo aplicações web com produtividade
JavaServer Faces - Desenvolvendo aplicações web com produtividadeRafael Ponte
 
Entendendo Domain-Driven Design
Entendendo Domain-Driven DesignEntendendo Domain-Driven Design
Entendendo Domain-Driven DesignRafael Ponte
 

Más de Rafael Ponte (20)

TechDay: 10 Features do Oracle que voce nao conhecia - CONNECT BY CLAUSE
TechDay: 10 Features do Oracle que voce nao conhecia - CONNECT BY CLAUSETechDay: 10 Features do Oracle que voce nao conhecia - CONNECT BY CLAUSE
TechDay: 10 Features do Oracle que voce nao conhecia - CONNECT BY CLAUSE
 
TechDay Retrospectiva 2018
TechDay Retrospectiva 2018TechDay Retrospectiva 2018
TechDay Retrospectiva 2018
 
Arquitetura Java - Escalando além do Hype
Arquitetura Java - Escalando além do HypeArquitetura Java - Escalando além do Hype
Arquitetura Java - Escalando além do Hype
 
Como treinar seu estagiario
Como treinar seu estagiarioComo treinar seu estagiario
Como treinar seu estagiario
 
Lidando com o Caos: Testando Código PLSQL em um Projeto Critico
Lidando com o Caos: Testando Código PLSQL em um Projeto CriticoLidando com o Caos: Testando Código PLSQL em um Projeto Critico
Lidando com o Caos: Testando Código PLSQL em um Projeto Critico
 
Como Apresentar Codigo em Slides - Javou #7 - 2016
Como Apresentar Codigo em Slides - Javou #7 - 2016Como Apresentar Codigo em Slides - Javou #7 - 2016
Como Apresentar Codigo em Slides - Javou #7 - 2016
 
Migrations for Java (Javou #4 - JavaCE)
Migrations for Java (Javou #4 - JavaCE)Migrations for Java (Javou #4 - JavaCE)
Migrations for Java (Javou #4 - JavaCE)
 
Hibernate efetivo (IA-2014 / Disturbing the Mind)
Hibernate efetivo (IA-2014 / Disturbing the Mind)Hibernate efetivo (IA-2014 / Disturbing the Mind)
Hibernate efetivo (IA-2014 / Disturbing the Mind)
 
Importancia dos Testes Automatizados no dia a dia (Don't Panic)
Importancia dos Testes Automatizados no dia a dia (Don't Panic)Importancia dos Testes Automatizados no dia a dia (Don't Panic)
Importancia dos Testes Automatizados no dia a dia (Don't Panic)
 
Importância dos testes automatizados no dia a dia
Importância dos testes automatizados no dia a diaImportância dos testes automatizados no dia a dia
Importância dos testes automatizados no dia a dia
 
Migrations for Java
Migrations for JavaMigrations for Java
Migrations for Java
 
Os 10 maus habitos dos desenvolvedores jsf (JustJava e CCT)
Os 10 maus habitos dos desenvolvedores jsf (JustJava e CCT)Os 10 maus habitos dos desenvolvedores jsf (JustJava e CCT)
Os 10 maus habitos dos desenvolvedores jsf (JustJava e CCT)
 
Importância dos testes automatizadoss
Importância dos testes automatizadossImportância dos testes automatizadoss
Importância dos testes automatizadoss
 
Greenbar - Testes automatizados na sua empresa
Greenbar - Testes automatizados na sua empresaGreenbar - Testes automatizados na sua empresa
Greenbar - Testes automatizados na sua empresa
 
Desafios de um desenvolvedor JSF
Desafios de um desenvolvedor JSFDesafios de um desenvolvedor JSF
Desafios de um desenvolvedor JSF
 
Curso de Java server faces (JSF)
Curso de Java server faces (JSF)Curso de Java server faces (JSF)
Curso de Java server faces (JSF)
 
Os 10 maus hábitos dos desenvolvedores JSF
Os 10 maus hábitos dos desenvolvedores JSFOs 10 maus hábitos dos desenvolvedores JSF
Os 10 maus hábitos dos desenvolvedores JSF
 
Boas Práticas com JavaServer Faces (Jsf)
Boas Práticas com JavaServer Faces (Jsf)Boas Práticas com JavaServer Faces (Jsf)
Boas Práticas com JavaServer Faces (Jsf)
 
JavaServer Faces - Desenvolvendo aplicações web com produtividade
JavaServer Faces - Desenvolvendo aplicações web com produtividadeJavaServer Faces - Desenvolvendo aplicações web com produtividade
JavaServer Faces - Desenvolvendo aplicações web com produtividade
 
Entendendo Domain-Driven Design
Entendendo Domain-Driven DesignEntendendo Domain-Driven Design
Entendendo Domain-Driven Design
 

Hibernate Efetivo: 6 dicas para não deixar sua app morrer

  • 1. Hibernate EFETIVO ERROS COMUNS E SOLUÇÕES Tuesday, August 7, 2012
  • 2. Eu estava me perguntando quando de fato o Hibernate foi criado... Tuesday, August 7, 2012
  • 3. Eu estava me perguntando quando de fato o Hibernate foi criado... O “Boom” foi em 2003! Luca Bastos Tuesday, August 7, 2012
  • 4. Quase uma década! 2012 - 2003 = 9 Tuesday, August 7, 2012
  • 5. mas ainda hoje... Tuesday, August 7, 2012
  • 6. mas ainda hoje... existem devs que subutilizam o framework Tuesday, August 7, 2012
  • 7. mas ainda hoje... existem devs que subutilizam o framework problemas de perfomance e escalabilidade Tuesday, August 7, 2012
  • 8. e pra piorar... Tuesday, August 7, 2012
  • 10. culpam o Hibernate A culpa é do Banco de Dados! Sérgio Tuesday, August 7, 2012
  • 11. é fácil culpar o que não se conhece... Tuesday, August 7, 2012
  • 12. um SGDB mal configurado pode ser o problema... Tuesday, August 7, 2012
  • 13. um SGDB mal configurado pode ser o problema... MAS na maioria das vezes o problema está na SUA APLICAÇÃO Tuesday, August 7, 2012
  • 14. tabelas sem índices <3 Tuesday, August 7, 2012
  • 15. tabelas sem índices consultas mal-feitas <3 <3 Tuesday, August 7, 2012
  • 16. tabelas sem índices consultas mal-feitas muitos hits ao banco Tuesday, August 7, 2012 <3 <3 <3
  • 17. tabelas sem índices consultas mal-feitas muitos hits ao banco connection leaks Tuesday, August 7, 2012 <3 <3 <3
  • 18. tabelas sem índices consultas mal-feitas muitos hits ao banco connection leaks memory leaks Tuesday, August 7, 2012 <3 <3 <3
  • 19. Não saber tirar proveito framework Tuesday, August 7, 2012
  • 20. Hibernate Efetivo 6 dicas para não deixar sua app morrer Tuesday, August 7, 2012
  • 23. Fortaleza - Terra do Sol Tuesday, August 7, 2012
  • 24. #1 POOL DE CONEXÕES Tuesday, August 7, 2012
  • 25. com certeza todos aqui já ouviram falar... Tuesday, August 7, 2012
  • 26. mas nem todos dão a devida atenção... Tuesday, August 7, 2012
  • 27. mas nem todos dão a devida atenção... até perceberem a app engasgando Tuesday, August 7, 2012
  • 28. mas nem todos dão a devida atenção... até perceberem a app engasgando ou até receberem um Tuesday, August 7, 2012
  • 29. mas nem todos dão a devida atenção... até perceberem a app engasgando ou até receberem um org.hibernate.exception.Gener icJDBCException: Cannot open connection Tuesday, August 7, 2012
  • 30. daí percebem que não configuraram o o pool do Hibernate hibernate.properties hibernate.connection.driver_class=org.postgresql.Driver hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect hibernate.connection.url=jdbc:postgresql://localhost:5432/myapp hibernate.connection.username=postgres hibernate.connection.password=1234 Tuesday, August 7, 2012
  • 31. daí percebem que não configuraram o o pool do Hibernate hibernate.properties hibernate.connection.driver_class=org.postgresql.Driver hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect hibernate.connection.url=jdbc:postgresql://localhost:5432/myapp hibernate.connection.username=postgres hibernate.connection.password=1234 hibernate.connection.pool_size=30 Tuesday, August 7, 2012
  • 32. daí percebem que não configuraram o o pool do Hibernate hibernate.properties hibernate.connection.driver_class=org.postgresql.Driver hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect hibernate.connection.url=jdbc:postgresql://localhost:5432/myapp hibernate.connection.username=postgres hibernate.connection.password=1234 hibernate.connection.pool_size=30 Tuesday, August 7, 2012
  • 33. a app volta a funcionar bem por um tempo Tuesday, August 7, 2012
  • 34. a app volta a funcionar bem por um tempo Tuesday, August 7, 2012
  • 35. e vão alocando mais conexões com o tempo hibernate.properties hibernate.connection.pool_size=30                                                              40                                                              55                                                              70                                                            ... Tuesday, August 7, 2012
  • 36. o pool PADRÃO do Hibernate Tuesday, August 7, 2012
  • 37. que possui uma impl. RUDIMENTAR Tuesday, August 7, 2012
  • 38. INFO DriverManagerConnectionProvider:64 - Using Hibernate built-in connection pool (not for production use!) INFO DriverManagerConnectionProvider:65 - Hibernate connection pool size: 20 Tuesday, August 7, 2012
  • 39. not for production use! INFO DriverManagerConnectionProvider:64 - Using Hibernate built-in connection pool (not for production use!) INFO DriverManagerConnectionProvider:65 - Hibernate connection pool size: 20 Tuesday, August 7, 2012
  • 42. temos ótimas opções... pools como c3p0 ou commons-dbcp Tuesday, August 7, 2012
  • 43. o Hibernate já vem com c3p0 Tuesday, August 7, 2012
  • 44. configurando c3p0 hibernate.properties hibernate.connection.driver_class=org.postgresql.Driver hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect hibernate.connection.url=jdbc:postgresql://localhost:5432/myapp hibernate.connection.username=postgres hibernate.connection.password=1234 hibernate.c3p0.min_size=5 hibernate.c3p0.max_size=20 hibernate.c3p0.timeout=1800 hibernate.c3p0.max_statements=50 Tuesday, August 7, 2012
  • 45. ou melhor ainda... Tuesday, August 7, 2012
  • 46. podemos obter as conexões de um DataSource <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"> ! <!-- access configuration --> ! <property name="driverClass" value="${jdbc.driverclass}" /> ! <property name="jdbcUrl" value="${jdbc.url}" /> ! <property name="user" value="${jdbc.username}" /> ! <property name="password" value="${jdbc.password}" /> ! <!-- pool sizing --> ! <property name="initialPoolSize" value="3" /> ! <property name="minPoolSize" value="6" /> ! <property name="maxPoolSize" value="25" /> ! <property name="acquireIncrement" value="3" /> ! <property name="maxStatements" value="0" /> ! <!-- retries --> ! <property name="acquireRetryAttempts" value="30" /> ! <property name="acquireRetryDelay" value="1000" /> <!-- 1s --> ! <property name="breakAfterAcquireFailure" value="false" /> ! <!-- refreshing connections --> ! <property name="maxIdleTime" value="180" /> <!-- 3min --> ! <property name="maxConnectionAge" value="10" /> <!-- 1h --> ! <!-- timeouts e testing --> ! <property name="checkoutTimeout" value="5000" /> <!-- 5s --> ! <property name="idleConnectionTestPeriod" value="60" /> <!-- 60 --> ! <property name="testConnectionOnCheckout" value="true" /> ! <property name="preferredTestQuery" value="SELECT 1+1" /> </bean> Tuesday, August 7, 2012
  • 47. Pool traz melhoria de performance Tuesday, August 7, 2012
  • 48. Pool traz melhoria de performance mas não faz milagres Tuesday, August 7, 2012
  • 49. #2 lidando com LazyInitialization Exception Tuesday, August 7, 2012
  • 50. quando e por que acontece? Tuesday, August 7, 2012
  • 51. @Entity class  NotaFiscal  {    …    @OneToMany    List<Item>  itens; } Tuesday, August 7, 2012
  • 52. Percorrendo os itens de uma nota NotaFiscal  nf  =  (NotaFiscal)  session.load (NotaFiscal.class,  42); List<Item>  itens  =  nf.getItens(); Tuesday, August 7, 2012
  • 53. Hibernate executa 2 selects NotaFiscal  nf  =  (NotaFiscal)  session.load(NotaFiscal.class,  42); select nf.* from NotaFiscal nf where nf.id=42 List<Item>  itens  =  nf.getItens(); select i.* from Item i where i.nota_fiscal_id=42 Tuesday, August 7, 2012
  • 54. a session do Hibernate foi fechada Session  session  =   sessionFactory.openSession(); NotaFiscal  nf  =  (NotaFiscal)  session.load (NotaFiscal.class,  42); session.close(); List<Item>  itens  =  nf.getItens(); System.out.println("numero  de  pedidos:"  +   itens.size()); Tuesday, August 7, 2012
  • 55. mas ao ler os itens da nota Session  session  =   sessionFactory.openSession(); NotaFiscal  nf  =  (NotaFiscal)  session.load org.hibernate.LazyInitializationException: (NotaFiscal.class,  42); failed to lazily session.close(); initialize a collection - no session or session was closed. List<Item>  itens  =  nf.getItens(); System.out.println("numero  de  pedidos:"  +   itens.size()); Tuesday, August 7, 2012
  • 56. resolver parece fácil, certo? Tuesday, August 7, 2012
  • 57. fechar a session ao término do trabalho Session  session  =   sessionFactory.openSession(); NotaFiscal  nf  =  (NotaFiscal)  session.load (NotaFiscal.class,  42); List<Item>  itens  =  nf.getItens(); System.out.println("numero  de  pedidos:"  +   itens.size()); session.close(); Tuesday, August 7, 2012
  • 58. Mas e quando estamos trabalhando na Web? Tuesday, August 7, 2012
  • 59. NotaFiscalController.java @Get("/notas/{id}") public  void  view(Long  id)  {    NotaFiscal  nf  =  notaFiscalDao.carrega(id);    result.include("nf",  nf);    result.forwardTo("/notas/view.jsp"); } view.jsp <c:forEach  var="item"  items="${nf.itens}">        ${item.produto.descricao}<br/> </c:forEach> Tuesday, August 7, 2012
  • 60. NotaFiscalController.java @Get("/notas/{id}") public  void  view(Long  id)  {    NotaFiscal  nf  =  notaFiscalDao.carrega(id);    result.include("nf",  nf);    result.forwardTo("/notas/view.jsp"); } LazyInitializationException view.jsp <c:forEach  var="item"  items="${nf.itens}">        ${item.produto.descricao}<br/> </c:forEach> Tuesday, August 7, 2012
  • 61. e agora? #comofas Tuesday, August 7, 2012
  • 62. e agora? #comofas passa tudo pra EAGER! ;D Sérgio Tuesday, August 7, 2012
  • 63. @Entity class  NotaFiscal  {    …    @OneToMany(fetch=FetchType.EAGER)    List<Item>  itens; } Tuesday, August 7, 2012
  • 64. Hibernate executa 1 select NotaFiscal  nf  =  (NotaFiscal)  session.load(NotaFiscal.class,  42); select nf.*, i.* from NotaFiscal nf left outer join Item i on nf.id = i.nota_fiscal_id where nf.id=42 Tuesday, August 7, 2012
  • 65. mas isso poderia gerar uma sobrecarga... Tuesday, August 7, 2012
  • 66. mas isso poderia gerar uma sobrecarga... pois os itens da nota não são necessários em muitos lugares Tuesday, August 7, 2012
  • 67. lembre-se que ter os relacionamentos como LAZY é uma boa prática Tuesday, August 7, 2012
  • 68. como evitar LIE sem modificar o relacionamento para EAGER? Tuesday, August 7, 2012
  • 69. Open Session In View Tuesday, August 7, 2012
  • 70. Servlet Filter @WebFilter(urlPatterns="/*") public  class  OpenSessionInViewFilter  implements  Filter  {   SessionFactory  sessionFactory;     @Override   public  void  doFilter(ServletRequest  req,  ServletResponse  res,   FilterChain  chain)  {   Transaction  transaction  =  null;              try  {                    Session  session  =  sessionFactory.getCurrentSession();              transaction  =  session.beginTransaction();                                chain.doFilter(req,  res);                                transaction.commit();     }  finally  {       if  (transaction  !=  null  &&  transaction.isActive())  {         transaction.rollback();       }     }   } } Tuesday, August 7, 2012
  • 71. o OSIV só evita LIE no mesmo request! Tuesday, August 7, 2012
  • 73. #3 Second Level Cache Tuesday, August 7, 2012
  • 74. Carregando uma nota por ID NotaFiscal  nf  =  (NotaFiscal)  session.load (NotaFiscal.class,  42); Tuesday, August 7, 2012
  • 75. Session Banco de Dados Tuesday, August 7, 2012
  • 76. First Level Cache Session Banco de Dados Tuesday, August 7, 2012
  • 77. Session Session Session Session Banco de Dados Tuesday, August 7, 2012
  • 78. Session Session Session Session Second Level Cache Banco de Dados Tuesday, August 7, 2012
  • 79. First Level Cache Session Session Session Session Second Level Cache Banco de Dados Tuesday, August 7, 2012
  • 80. Session Session Session Session SessionFactory Banco de Dados Tuesday, August 7, 2012
  • 82. #1 configuramos o Hibernate hibernate.properties hibernate.cache.use_second_level_cache=true hibernate.cache.region.factory_class=net.sf.ehcac he.hibernate.EhCacheRegionFactory Tuesday, August 7, 2012
  • 83. #2 configuramos as entidades @Entity @Cache(usage=CacheConcurrencyStrategy.READ_WRITE) class  Issue  { @Id    private  Long  id; private  String  descricao; private  String  status; @ManyToOne private  Projeto  projeto;    @OneToMany    private  List<Comentario>  comentarios; } Tuesday, August 7, 2012
  • 84. Caching Strategy @Cache( usage=CacheConcurrencyStrategy.READ_WRITE) READ_ONLY NONSTRICT_READ_WRITE READ_WRITE Tuesday, August 7, 2012
  • 85. Caching Strategy @Cache( usage=CacheConcurrencyStrategy.READ_WRITE) READ_ONLY Melhor performance NONSTRICT_READ_WRITE READ_WRITE Tuesday, August 7, 2012
  • 86. Caching Strategy @Cache( usage=CacheConcurrencyStrategy.READ_WRITE) READ_ONLY NONSTRICT_READ_WRITE Dados não críticos READ_WRITE Tuesday, August 7, 2012
  • 87. Caching Strategy @Cache( usage=CacheConcurrencyStrategy.READ_WRITE) READ_ONLY NONSTRICT_READ_WRITE READ_WRITE Modificações frequentes Tuesday, August 7, 2012
  • 88. ehcache.xml <cache        name="br.com.triadworks.model.Issue"        maxElementsInMemory="10000"        eternal="false"        timeToIdleSeconds="1800"        timeToLiveSeconds="10000"        overflowToDisk="true"        memoryStoreEvictionPolicy="LRU" /> Tuesday, August 7, 2012
  • 89. Como 2nd Level Cache funciona? Tuesday, August 7, 2012
  • 90. 2nd Level Cache não faz cache das instancias das entidades Tuesday, August 7, 2012
  • 91. 2nd Level Cache não faz cache das instancias das entidades somente dos valores das propriedades Tuesday, August 7, 2012
  • 92. @Entity @Cache(usage=CacheConcurrencyStrategy.READ_WRITE) class  Issue  { @Id    private  Long  id; private  String  descricao; private  String  status; @ManyToOne private  Projeto  projeto;    @OneToMany    private  List<Comentario>  comentarios; } Tuesday, August 7, 2012
  • 93. modelo conceitual do cache Issue Data Cache 17 -> [ “Bug #1”, “ABERTA” , 1 ] 18 -> [ “Bug #2”, “FECHADA”, 2 ] 19 -> [ “Bug #3”, “ABERTA” , 1 ] Tuesday, August 7, 2012
  • 94. modelo conceitual do cache Issue Data Cache 17 -> [ “Bug #1”, “ABERTA” , 1 ] 18 -> [ “Bug #2”, “FECHADA”, 2 ] 19 -> [ “Bug #3”, “ABERTA” , 1 ] não é uma árvore de objetos, mas sim um "Map de Arrays" Tuesday, August 7, 2012
  • 95. 2nd Level Cache não faz cache das associações Tuesday, August 7, 2012
  • 96. @Entity @Cache(usage=CacheConcurrencyStrategy.READ_WRITE) class  Issue  { @Id    private  Long  id; private  String  descricao; private  String  status; @ManyToOne private  Projeto  projeto;    @OneToMany    @Cache(usage=CacheConcurrencyStrategy.READ_WRITE)    private  List<Comentario>  comentarios; } Tuesday, August 7, 2012
  • 97. modelo conceitual do cache Issue Data Cache 17 -> [ “Bug #1”, “ABERTA” , 1, [1,2] ] 18 -> [ “Bug #2”, “FECHADA”, 2, [] ] 19 -> [ “Bug #3”, “ABERTA” , 1, [3] ] Tuesday, August 7, 2012
  • 98. Devo cachear todas as minhas entidades? Tuesday, August 7, 2012
  • 99. Com 2nd Level Cache tudo funciona bem enquanto buscamos por ID... session.load(Issue.class,  17); Tuesday, August 7, 2012
  • 100. Com 2nd Level Cache tudo funciona bem enquanto buscamos por ID... session.load(Issue.class,  17); ...mas e quando precisamos de uma consulta um pouco diferente? session    .createQuery("from  Issue  where  status  =  ?")    .setString(0,"ABERTO")    .list();   Tuesday, August 7, 2012
  • 101. #4 Query Cache Tuesday, August 7, 2012
  • 102. Query Cache faz cache do resultado de uma query Tuesday, August 7, 2012
  • 103. Configurando Hibernate para usar Query Cache hibernate.properties hibernate.cache.use_query_cache=true Tuesday, August 7, 2012
  • 104. Query Cache session    .createQuery("from  Issue  where  status  =  ?")    .setString(0,  status)    .setCacheable(true)    .list();   Tuesday, August 7, 2012
  • 105. modelo conceitual do query cache Query Cache [“from Issue where status = ?”, [“ABERTA”]] -> [17, 19] Tuesday, August 7, 2012
  • 106. modelo conceitual do query cache Query Cache [“from Issue where status = ?”, [“ABERTA”]] -> [17, 19] Query + Parâmetros IDs Tuesday, August 7, 2012
  • 107. por isso Query Cache SEM 2nd Level Cache não é de muita ajuda Tuesday, August 7, 2012
  • 108. Utilize somente em consultas que são executadas repetidas vezes com os mesmos parâmetros Tuesday, August 7, 2012
  • 109. Utilize somente em consultas que são executadas repetidas vezes com os mesmos parâmetros Tuesday, August 7, 2012
  • 110. #5 Select n+1 Tuesday, August 7, 2012
  • 111. o campeão em prejudicar a performance da aplicação Tuesday, August 7, 2012
  • 112. Processando os itens de uma nota NotaFiscal  nf  =  (NotaFiscal)  session.load (NotaFiscal.class,  42); processaItensDaNota(nf); Tuesday, August 7, 2012
  • 113. Hibernate executa 2 selects NotaFiscal  nf  =  (NotaFiscal)  session.load(NotaFiscal.class,  42); select nf.* from NotaFiscal nf where nf.id=42 processaItensDaNota(nf); select i.* from Item i where i.nota_fiscal_id=42 Tuesday, August 7, 2012
  • 114. Processando os itens de varias notas List<NotaFiscal>  notas  =  dao.listaTudo(); for  (NotaFiscal  nf  :  notas)  {        processaItensDaNota(nf); } Tuesday, August 7, 2012
  • 115. Hibernate executa n+1 selects List<NotaFiscal>  notas  =  dao.listaTudo(); select nf.* from NotaFiscal nf for  (NotaFiscal  nf  :  notas)  {        processaItensDaNota(nf); } select i.* from Item i where i.nota_fiscal_id=? select i.* from Item i where i.nota_fiscal_id=? select i.* from Item i where i.nota_fiscal_id=? select i.* from Item i where i.nota_fiscal_id=? select i.* from Item i where i.nota_fiscal_id=? ... Tuesday, August 7, 2012
  • 116. são muitos hits no banco de dados Tuesday, August 7, 2012
  • 117. são muitos hits no banco de dados mas podemos resolver isso... Tuesday, August 7, 2012
  • 119. #1 EAGER ou join- fetch Tuesday, August 7, 2012
  • 120. Utilizando FetchMode=EAGER @Entity class  NotaFiscal  {    …    @OneToMany(fetch=FetchType.EAGER)    List<Item>  itens; } Tuesday, August 7, 2012
  • 121. Hibernate executa 1 select List<NotaFiscal>  notas  =  dao.listaTudo(); select nf.*, i.* from NotaFiscal nf left outer join Item i on nf.id = i.nota_fiscal_id Tuesday, August 7, 2012
  • 122. antes de definir um mapeamento global deste tipo você precisa se perguntar... Tuesday, August 7, 2012
  • 123. SEMPRE que uma nota é necessária, todos seus itens também são necessários? Tuesday, August 7, 2012
  • 125. Utilizando Join Fetch session    .createQuery("from  NotaFiscal  n   left  join  fetch  n.itens")    .list();   Tuesday, August 7, 2012
  • 126. #2 batch-size nas associações Tuesday, August 7, 2012
  • 127. É o meio termo entre EAGER e LAZY Tuesday, August 7, 2012
  • 128. @BatchSize @Entity class  NotaFiscal  {    …    @OneToMany    @BatchSize(size=10)    List<Item>  itens; } Tuesday, August 7, 2012
  • 129. Hibernate executa n/10+1 selects List<NotaFiscal>  notas  =  dao.listaTudo(); select nf.* from NotaFiscal nf for  (NotaFiscal  nf  :  notas)  {        processaItensDaNota(nf); } select i.* from Item i where i.nota_fiscal_id in (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) select i.* from Item i where i.nota_fiscal_id in (?, ?, ?, ?, ?) Tuesday, August 7, 2012
  • 130. @BatchSize também é conhecido como: Tuesday, August 7, 2012
  • 131. @BatchSize também é conhecido como: otimização de adivinhação cega (blind-guess optimization) Tuesday, August 7, 2012
  • 132. @BatchSize também é conhecido como: otimização de adivinhação cega (blind-guess optimization) ou seja, é um palpite Tuesday, August 7, 2012
  • 133. #3 FetchMode SUBSELECT Tuesday, August 7, 2012
  • 134. SUBSELECT @Entity class  NotaFiscal  {    …    @OneToMany    @Fetch(FetchMode.SUBSELECT)    List<Item>  itens; } Tuesday, August 7, 2012
  • 135. Hibernate executa 2 selects List<NotaFiscal>  notas  =  dao.listaTudo(); select nf.* from NotaFiscal nf for  (NotaFiscal  nf  :  notas)  {        processaItensDaNota(nf); } select i.* from Item i where i.nota_fiscal_id in (select nf.id from NotaFiscal nf) Tuesday, August 7, 2012
  • 137. Qual utilizar? depende Tuesday, August 7, 2012
  • 138. #6 Processamento em lote Tuesday, August 7, 2012
  • 139. Imagine que temos que importar 100k produtos para o banco de dados Tuesday, August 7, 2012
  • 140. Session  session  =  sf.openSession(); Transaction  tx  =  session.beginTransaction();     for  (  int  i=0;  i  <  100000;  i++  )  {   Produto  produto  =  new  Produto(...);   session.save(produto); }     tx.commit(); session.close(); Tuesday, August 7, 2012
  • 141. em ~50k produtos nós receberíamos um OutOfMemoryException Tuesday, August 7, 2012
  • 143. Hibernate faz cache de todas as instâncias dos Produtos inseridos na Session Tuesday, August 7, 2012
  • 144. mas como melhorar? Tuesday, August 7, 2012
  • 145. Session  session  =  sf.openSession(); Transaction  tx  =  session.beginTransaction();     for  (  int  i=0;  i  <  100000;  i++  )  {   Produto  produto  =  new  Produto(...);   session.save(produto);    if  (i  %  100  ==  0)  {        session.flush();        session.clear();    } }     tx.commit(); session.close(); Tuesday, August 7, 2012
  • 147. evitamos o OutOfMemoryException Mas o processamento ainda continua lento! Tuesday, August 7, 2012
  • 148. evitamos o OutOfMemoryException Mas o processamento ainda continua lento! Dá pra melhorar? Tuesday, August 7, 2012
  • 150. JDBC puro? código de maxu! Handerson Frota Tuesday, August 7, 2012
  • 152. API mais baixo nível próxima ao jdbc sem 1st Level Cache mapeamento básico sem 2nd Level Cache StatelessSession sem cascade sem dirty-checking Collections são ignorados sem modelo de sem interceptors eventos Tuesday, August 7, 2012
  • 153. StatelessSession  session  =   sf.openStatelessSession(); Transaction  tx  =  session.beginTransaction();     for  (  int  i=0;  i  <  100000;  i++  )  {   Produto  produto  =  new  Produto(...);   session.insert(produto); }     tx.commit(); session.close(); Tuesday, August 7, 2012
  • 154. menos consumo de memória e mais rápida! Tuesday, August 7, 2012
  • 155. dá pra melhorar? Yuri Adams menos consumo de memória e mais rápida! Tuesday, August 7, 2012
  • 158. Foi apenas a ponta o iceberg! Tuesday, August 7, 2012
  • 159. cada uma destas dicas são simples, mas requerem mais estudo Tuesday, August 7, 2012
  • 160. cada uma destas dicas são simples, mas requerem mais estudo pois depende do projeto Tuesday, August 7, 2012
  • 161. um DBA certamente pode ter ajudar em muitos cenários Tuesday, August 7, 2012
  • 162. Hibernate não é seu inimigo, deixem de #mimimi Tuesday, August 7, 2012
  • 163. Rafael Ponte rponte@triadworks.com.br Tuesday, August 7, 2012