Hibernate EFETIVO                          ERROS COMUNS E SOLUÇÕESTuesday, 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!      L...
Quase uma década!                             2012 - 2003 = 9Tuesday, August 7, 2012
mas ainda hoje...Tuesday, August 7, 2012
mas ainda hoje...  existem devs que  subutilizam o frameworkTuesday, August 7, 2012
mas ainda hoje...  existem devs que  subutilizam o framework          problemas de perfomance               e escalabilida...
e pra piorar...Tuesday, August 7, 2012
culpam o HibernateTuesday, August 7, 2012
culpam o Hibernate                          A culpa é do Banco de                                 Dados!          SérgioTu...
é 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 vez...
tabelas sem índices                                        <3Tuesday, August 7, 2012
tabelas sem índices                            consultas mal-feitas                                        <3 <3Tuesday, A...
tabelas sem índices                            consultas mal-feitas  muitos hits ao bancoTuesday, August 7, 2012          ...
tabelas sem índices                               consultas mal-feitas  muitos hits ao banco                          conn...
tabelas sem índices                                 consultas mal-feitas  muitos hits ao banco                            ...
Não saber tirar                          proveito frameworkTuesday, August 7, 2012
Hibernate Efetivo                           6 dicas para não deixar                               sua app morrerTuesday, A...
@rponteTuesday, August 7, 2012
Tuesday, August 7, 2012
Fortaleza - Terra do SolTuesday, August 7, 2012
#1                           POOL DE                          CONEXÕESTuesday, 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 engasgandoTuesday, August 7, 2012
mas nem todos dão a devida atenção...              até perceberem a app engasgando      ou até receberem umTuesday, August...
mas nem todos dão a devida atenção...              até perceberem a app engasgando      ou até receberem um         org.hi...
daí percebem que não configuraram o                               o pool do Hibernate                                      ...
daí percebem que não configuraram o                               o pool do Hibernate                                      ...
daí percebem que não configuraram o                               o pool do Hibernate                                      ...
a app volta a funcionar                      bem por um tempoTuesday, August 7, 2012
a app volta a funcionar                      bem por um tempoTuesday, August 7, 2012
e vão alocando mais conexões com o                                         tempo                                          ...
o pool PADRÃO do                          HibernateTuesday, August 7, 2012
que possui uma impl.                            RUDIMENTARTuesday, August 7, 2012
INFO DriverManagerConnectionProvider:64 - Using Hibernate built-in  connection pool (not for production use!)  INFO Driver...
not for production use!  INFO DriverManagerConnectionProvider:64 - Using Hibernate built-in  connection pool (not for prod...
qual pool utilizar?Tuesday, August 7, 2012
temos ótimas opções...Tuesday, August 7, 2012
temos ótimas opções...                          pools como c3p0 ou                           commons-dbcpTuesday, August 7...
o Hibernate já vem                              com c3p0Tuesday, August 7, 2012
configurando c3p0                                     hibernate.properties  hibernate.connection.driver_class=org.postgresq...
ou melhor ainda...Tuesday, August 7, 2012
podemos obter as conexões de um DataSource               <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataS...
Pool traz melhoria de                              performanceTuesday, August 7, 2012
Pool traz melhoria de                              performance                  mas não faz milagresTuesday, August 7, 2012
#2                              lidando com                          LazyInitialization                             Except...
quando e por que acontece?Tuesday, August 7, 2012
@Entity                          class	  NotaFiscal	  {                          	  	  …                          	  	  @O...
Percorrendo os itens de uma nota               NotaFiscal	  nf	  =	  (NotaFiscal)	  session.load               (NotaFiscal...
Hibernate executa 2 selects    NotaFiscal	  nf	  =	  (NotaFiscal)	  session.load(NotaFiscal.class,	  42);                s...
a session do Hibernate foi fechada               Session	  session	  =	                 sessionFactory.openSession();     ...
mas ao ler os itens da nota               Session	  session	  =	                 sessionFactory.openSession();            ...
resolver parece fácil, certo?Tuesday, August 7, 2012
fechar a session ao término do trabalho               Session	  session	  =	                 sessionFactory.openSession();...
Mas e quando estamos                           trabalhando na Web?Tuesday, August 7, 2012
NotaFiscalController.java         @Get("/notas/{id}")         public	  void	  view(Long	  id)	  {         	  	  NotaFiscal...
NotaFiscalController.java         @Get("/notas/{id}")         public	  void	  view(Long	  id)	  {         	  	  NotaFiscal...
e agora? #comofasTuesday, August 7, 2012
e agora? #comofas                                passa tudo pra                                  EAGER! ;D            Sérg...
@Entity     class	  NotaFiscal	  {     	  	  …     	  	  @OneToMany(fetch=FetchType.EAGER)     	  	  List<Item>	  itens;  ...
Hibernate executa 1 select NotaFiscal	  nf	  =	  (NotaFiscal)	  session.load(NotaFiscal.class,	  42);      select nf.*, i....
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...
lembre-se que ter os        relacionamentos como LAZY é                uma boa práticaTuesday, August 7, 2012
como evitar LIE sem                          modificar o relacionamento                                       para EAGER?Tu...
Open Session In                       ViewTuesday, August 7, 2012
Servlet Filter     @WebFilter(urlPatterns="/*")     public	  class	  OpenSessionInViewFilter	  implements	  Filter	  {    ...
o OSIV só evita LIE no                       mesmo request!Tuesday, August 7, 2012
anti-pattern?Tuesday, August 7, 2012
#3                          Second Level                             CacheTuesday, August 7, 2012
Carregando uma nota por ID               NotaFiscal	  nf	  =	  (NotaFiscal)	  session.load               (NotaFiscal.class...
Session                          Banco de DadosTuesday, August 7, 2012
First Level Cache                             Session                          Banco de DadosTuesday, August 7, 2012
Session   Session   Session   Session                                     Banco de DadosTuesday, August 7, 2012
Session   Session    Session   Session                                    Second Level Cache                              ...
First Level Cache                          Session   Session    Session      Session                                    Se...
Session   Session    Session   Session                                      SessionFactory                                ...
Configurar é simplesTuesday, August 7, 2012
#1 configuramos o Hibernate                                          hibernate.properties  hibernate.cache.use_second_level...
#2 configuramos as entidades   @Entity   @Cache(usage=CacheConcurrencyStrategy.READ_WRITE)   class	  Issue	  {          @Id...
Caching Strategy   @Cache(     usage=CacheConcurrencyStrategy.READ_WRITE)           READ_ONLY      NONSTRICT_READ_WRITE   ...
Caching Strategy   @Cache(     usage=CacheConcurrencyStrategy.READ_WRITE)           READ_ONLY          Melhor performance ...
Caching Strategy   @Cache(     usage=CacheConcurrencyStrategy.READ_WRITE)           READ_ONLY      NONSTRICT_READ_WRITE   ...
Caching Strategy   @Cache(     usage=CacheConcurrencyStrategy.READ_WRITE)           READ_ONLY      NONSTRICT_READ_WRITE   ...
ehcache.xml                 <cache                 	  	  	  	  name="br.com.triadworks.model.Issue"                 	  	  ...
Como 2nd Level Cache                      funciona?Tuesday, August 7, 2012
2nd Level Cache não faz cache                   das instancias das entidadesTuesday, August 7, 2012
2nd Level Cache não faz cache                   das instancias das entidades                 somente dos valores          ...
@Entity   @Cache(usage=CacheConcurrencyStrategy.READ_WRITE)   class	  Issue	  {          @Id   	  	  private	  Long	  id; ...
modelo conceitual do cache                          Issue Data Cache        17 -> [ “Bug #1”, “ABERTA” , 1 ]        18 -> ...
modelo conceitual do cache                            Issue Data Cache        17 -> [ “Bug #1”, “ABERTA” , 1 ]        18 -...
2nd Level Cache não faz cache                         das associaçõesTuesday, August 7, 2012
@Entity   @Cache(usage=CacheConcurrencyStrategy.READ_WRITE)   class	  Issue	  {          @Id   	  	  private	  Long	  id; ...
modelo conceitual do cache                          Issue Data Cache        17 -> [ “Bug #1”, “ABERTA” , 1, [1,2] ]       ...
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);Tues...
Com 2nd Level Cache tudo funciona bem    enquanto buscamos por ID...                  session.load(Issue.class,	  17);    ...
#4                          Query CacheTuesday, August 7, 2012
Query Cache faz cache do                           resultado de uma queryTuesday, August 7, 2012
Configurando Hibernate para                          usar Query Cache                                          hibernate.pr...
Query Cache   session   	  	  .createQuery("from	  Issue	  where	  status	  =	  ?")   	  	  .setString(0,	  status)   	  	...
modelo conceitual do query cache                          Query Cache [“from Issue where status = ?”, [“ABERTA”]] -> [17, ...
modelo conceitual do query cache                                    Query Cache [“from Issue where status = ?”, [“ABERTA”]...
por isso Query Cache SEM                           2nd Level Cache não é de                                  muita ajudaTu...
Utilize somente em consultas                     que são executadas repetidas                      vezes com os mesmos    ...
Utilize somente em consultas                     que são executadas repetidas                      vezes com os mesmos    ...
#5                          Select n+1Tuesday, August 7, 2012
o campeão em prejudicar                              a performance da                                  aplicaçãoTuesday, A...
Processando os itens de uma nota               NotaFiscal	  nf	  =	  (NotaFiscal)	  session.load               (NotaFiscal...
Hibernate executa 2 selects    NotaFiscal	  nf	  =	  (NotaFiscal)	  session.load(NotaFiscal.class,	  42);                s...
Processando os itens de varias notas               List<NotaFiscal>	  notas	  =	  dao.listaTudo();               for	  (No...
Hibernate executa n+1 selects    List<NotaFiscal>	  notas	  =	  dao.listaTudo();                   select nf.* from NotaFi...
são muitos hits no banco de  dadosTuesday, August 7, 2012
são muitos hits no banco de  dados                          mas podemos resolver                                         i...
3 soluçõesTuesday, August 7, 2012
#1 EAGER ou join-                               fetchTuesday, August 7, 2012
Utilizando FetchMode=EAGER     @Entity     class	  NotaFiscal	  {     	  	  …     	  	  @OneToMany(fetch=FetchType.EAGER) ...
Hibernate executa 1 select  List<NotaFiscal>	  notas	  =	  dao.listaTudo();      select nf.*, i.* from NotaFiscal     nf l...
antes de definir um                          mapeamento global deste                              tipo você precisa se     ...
SEMPRE que uma nota é                           necessária, todos seus                             itens também são       ...
não?Tuesday, August 7, 2012
Utilizando Join Fetch   session   	  	  .createQuery("from	  NotaFiscal	  n	     left	  join	  fetch	  n.itens")   	  	  ....
#2 batch-size nas                            associaçõesTuesday, August 7, 2012
É o meio termo entre                             EAGER e LAZYTuesday, August 7, 2012
@BatchSize     @Entity     class	  NotaFiscal	  {     	  	  …     	  	  @OneToMany     	  	  @BatchSize(size=10)     	  	 ...
Hibernate executa n/10+1 selects    List<NotaFiscal>	  notas	  =	  dao.listaTudo();                   select nf.* from Not...
@BatchSize também é  conhecido como:Tuesday, August 7, 2012
@BatchSize também é  conhecido como:           otimização de adivinhação cega                          (blind-guess optimi...
@BatchSize também é  conhecido como:           otimização de adivinhação cega                          (blind-guess optimi...
#3 FetchMode                           SUBSELECTTuesday, August 7, 2012
SUBSELECT     @Entity     class	  NotaFiscal	  {     	  	  …     	  	  @OneToMany     	  	  @Fetch(FetchMode.SUBSELECT)   ...
Hibernate executa 2 selects    List<NotaFiscal>	  notas	  =	  dao.listaTudo();                   select nf.* from NotaFisc...
Qual utilizar?Tuesday, August 7, 2012
Qual utilizar?                          dependeTuesday, August 7, 2012
#6                          Processamento                             em loteTuesday, August 7, 2012
Imagine que temos que                     importar 100k produtos para                          o banco de dadosTuesday, Au...
Session	  session	  =	  sf.openSession();     Transaction	  tx	  =	  session.beginTransaction();     	   	       for	  (	 ...
em ~50k produtos nós                             receberíamos um                          OutOfMemoryExceptionTuesday, Aug...
por que?Tuesday, August 7, 2012
Hibernate faz cache de todas                       as instâncias dos Produtos                           inseridos na Sessi...
mas como melhorar?Tuesday, August 7, 2012
Session	  session	  =	  sf.openSession();     Transaction	  tx	  =	  session.beginTransaction();     	   	       for	  (	 ...
evitamos o OutOfMemoryExceptionTuesday, August 7, 2012
evitamos o OutOfMemoryException                          Mas o processamento ainda                                     con...
evitamos o OutOfMemoryException                          Mas o processamento ainda                                     con...
JDBC puro?Tuesday, August 7, 2012
JDBC puro?                             código de maxu!   Handerson FrotaTuesday, August 7, 2012
StatelessSessionTuesday, August 7, 2012
API mais baixo nível                                                         próxima ao jdbc                          sem ...
StatelessSession	  session	  =	       sf.openStatelessSession();     Transaction	  tx	  =	  session.beginTransaction();   ...
menos consumo de memória              e mais rápida!Tuesday, August 7, 2012
dá pra melhorar?                                             Yuri Adams        menos consumo de memória              e mai...
hibernate.properties  hibernate.jdbc.batch_size=50Tuesday, August 7, 2012
CONCLUSÃOTuesday, August 7, 2012
Foi apenas a ponta o iceberg!Tuesday, August 7, 2012
cada uma destas dicas são simples,             mas requerem mais estudoTuesday, August 7, 2012
cada uma destas dicas são simples,             mas requerem mais estudo              pois depende do projetoTuesday, Augus...
um DBA certamente pode ter                    ajudar em muitos cenáriosTuesday, August 7, 2012
Hibernate não é seu inimigo,                              deixem de #mimimiTuesday, August 7, 2012
Rafael Ponte                          rponte@triadworks.com.brTuesday, August 7, 2012
Upcoming SlideShare
Loading in...5
×

Hibernate Efetivo (QCONSP-2012)

15,085

Published on

Mesmo anos após o lançamento do Hibernate ainda é fácil encontrar projetos utilizando o framework de maneira ineficiente, podendo leva-lo a problemas sérios de performance ou até inviabilizar a aplicação. O uso não efetivo do Hibernate está intimamente ligado a erros comuns e más práticas em sua utilização, que vão desde pool de conexões, select n+1, configuração de cache, batch-size até o uso indevido do cache level 1 em processamentos batch e o tratamento de LazyInitializationException.

0 Comments
34 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
15,085
On Slideshare
0
From Embeds
0
Number of Embeds
10
Actions
Shares
0
Downloads
367
Comments
0
Likes
34
Embeds 0
No embeds

No notes for slide

Hibernate Efetivo (QCONSP-2012)

  1. 1. Hibernate EFETIVO ERROS COMUNS E SOLUÇÕESTuesday, August 7, 2012
  2. 2. Eu estava me perguntando quando de fato o Hibernate foi criado...Tuesday, August 7, 2012
  3. 3. Eu estava me perguntando quando de fato o Hibernate foi criado... O “Boom” foi em 2003! Luca BastosTuesday, August 7, 2012
  4. 4. Quase uma década! 2012 - 2003 = 9Tuesday, August 7, 2012
  5. 5. mas ainda hoje...Tuesday, August 7, 2012
  6. 6. mas ainda hoje... existem devs que subutilizam o frameworkTuesday, August 7, 2012
  7. 7. mas ainda hoje... existem devs que subutilizam o framework problemas de perfomance e escalabilidadeTuesday, August 7, 2012
  8. 8. e pra piorar...Tuesday, August 7, 2012
  9. 9. culpam o HibernateTuesday, August 7, 2012
  10. 10. culpam o Hibernate A culpa é do Banco de Dados! SérgioTuesday, August 7, 2012
  11. 11. é fácil culpar o que não se conhece...Tuesday, August 7, 2012
  12. 12. um SGDB mal configurado pode ser o problema...Tuesday, August 7, 2012
  13. 13. um SGDB mal configurado pode ser o problema... MAS na maioria das vezes o problema está na SUA APLICAÇÃOTuesday, August 7, 2012
  14. 14. tabelas sem índices <3Tuesday, August 7, 2012
  15. 15. tabelas sem índices consultas mal-feitas <3 <3Tuesday, August 7, 2012
  16. 16. tabelas sem índices consultas mal-feitas muitos hits ao bancoTuesday, August 7, 2012 <3 <3 <3
  17. 17. tabelas sem índices consultas mal-feitas muitos hits ao banco connection leaksTuesday, August 7, 2012 <3 <3 <3
  18. 18. tabelas sem índices consultas mal-feitas muitos hits ao banco connection leaks memory leaksTuesday, August 7, 2012 <3 <3 <3
  19. 19. Não saber tirar proveito frameworkTuesday, August 7, 2012
  20. 20. Hibernate Efetivo 6 dicas para não deixar sua app morrerTuesday, August 7, 2012
  21. 21. @rponteTuesday, August 7, 2012
  22. 22. Tuesday, August 7, 2012
  23. 23. Fortaleza - Terra do SolTuesday, August 7, 2012
  24. 24. #1 POOL DE CONEXÕESTuesday, August 7, 2012
  25. 25. com certeza todos aqui já ouviram falar...Tuesday, August 7, 2012
  26. 26. mas nem todos dão a devida atenção...Tuesday, August 7, 2012
  27. 27. mas nem todos dão a devida atenção... até perceberem a app engasgandoTuesday, August 7, 2012
  28. 28. mas nem todos dão a devida atenção... até perceberem a app engasgando ou até receberem umTuesday, August 7, 2012
  29. 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 connectionTuesday, August 7, 2012
  30. 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=1234Tuesday, August 7, 2012
  31. 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=30Tuesday, August 7, 2012
  32. 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=30Tuesday, August 7, 2012
  33. 33. a app volta a funcionar bem por um tempoTuesday, August 7, 2012
  34. 34. a app volta a funcionar bem por um tempoTuesday, August 7, 2012
  35. 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. 36. o pool PADRÃO do HibernateTuesday, August 7, 2012
  37. 37. que possui uma impl. RUDIMENTARTuesday, August 7, 2012
  38. 38. INFO DriverManagerConnectionProvider:64 - Using Hibernate built-in connection pool (not for production use!) INFO DriverManagerConnectionProvider:65 - Hibernate connection pool size: 20Tuesday, August 7, 2012
  39. 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: 20Tuesday, August 7, 2012
  40. 40. qual pool utilizar?Tuesday, August 7, 2012
  41. 41. temos ótimas opções...Tuesday, August 7, 2012
  42. 42. temos ótimas opções... pools como c3p0 ou commons-dbcpTuesday, August 7, 2012
  43. 43. o Hibernate já vem com c3p0Tuesday, August 7, 2012
  44. 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=50Tuesday, August 7, 2012
  45. 45. ou melhor ainda...Tuesday, August 7, 2012
  46. 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. 47. Pool traz melhoria de performanceTuesday, August 7, 2012
  48. 48. Pool traz melhoria de performance mas não faz milagresTuesday, August 7, 2012
  49. 49. #2 lidando com LazyInitialization ExceptionTuesday, August 7, 2012
  50. 50. quando e por que acontece?Tuesday, August 7, 2012
  51. 51. @Entity class  NotaFiscal  {    …    @OneToMany    List<Item>  itens; }Tuesday, August 7, 2012
  52. 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. 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=42Tuesday, August 7, 2012
  54. 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. 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. 56. resolver parece fácil, certo?Tuesday, August 7, 2012
  57. 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. 58. Mas e quando estamos trabalhando na Web?Tuesday, August 7, 2012
  59. 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. 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. 61. e agora? #comofasTuesday, August 7, 2012
  62. 62. e agora? #comofas passa tudo pra EAGER! ;D SérgioTuesday, August 7, 2012
  63. 63. @Entity class  NotaFiscal  {    …    @OneToMany(fetch=FetchType.EAGER)    List<Item>  itens; }Tuesday, August 7, 2012
  64. 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=42Tuesday, August 7, 2012
  65. 65. mas isso poderia gerar uma sobrecarga...Tuesday, August 7, 2012
  66. 66. mas isso poderia gerar uma sobrecarga... pois os itens da nota não são necessários em muitos lugaresTuesday, August 7, 2012
  67. 67. lembre-se que ter os relacionamentos como LAZY é uma boa práticaTuesday, August 7, 2012
  68. 68. como evitar LIE sem modificar o relacionamento para EAGER?Tuesday, August 7, 2012
  69. 69. Open Session In ViewTuesday, August 7, 2012
  70. 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. 71. o OSIV só evita LIE no mesmo request!Tuesday, August 7, 2012
  72. 72. anti-pattern?Tuesday, August 7, 2012
  73. 73. #3 Second Level CacheTuesday, August 7, 2012
  74. 74. Carregando uma nota por ID NotaFiscal  nf  =  (NotaFiscal)  session.load (NotaFiscal.class,  42);Tuesday, August 7, 2012
  75. 75. Session Banco de DadosTuesday, August 7, 2012
  76. 76. First Level Cache Session Banco de DadosTuesday, August 7, 2012
  77. 77. Session Session Session Session Banco de DadosTuesday, August 7, 2012
  78. 78. Session Session Session Session Second Level Cache Banco de DadosTuesday, August 7, 2012
  79. 79. First Level Cache Session Session Session Session Second Level Cache Banco de DadosTuesday, August 7, 2012
  80. 80. Session Session Session Session SessionFactory Banco de DadosTuesday, August 7, 2012
  81. 81. Configurar é simplesTuesday, August 7, 2012
  82. 82. #1 configuramos o Hibernate hibernate.properties hibernate.cache.use_second_level_cache=true hibernate.cache.region.factory_class=net.sf.ehcac he.hibernate.EhCacheRegionFactoryTuesday, August 7, 2012
  83. 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. 84. Caching Strategy @Cache( usage=CacheConcurrencyStrategy.READ_WRITE) READ_ONLY NONSTRICT_READ_WRITE READ_WRITETuesday, August 7, 2012
  85. 85. Caching Strategy @Cache( usage=CacheConcurrencyStrategy.READ_WRITE) READ_ONLY Melhor performance NONSTRICT_READ_WRITE READ_WRITETuesday, August 7, 2012
  86. 86. Caching Strategy @Cache( usage=CacheConcurrencyStrategy.READ_WRITE) READ_ONLY NONSTRICT_READ_WRITE Dados não críticos READ_WRITETuesday, August 7, 2012
  87. 87. Caching Strategy @Cache( usage=CacheConcurrencyStrategy.READ_WRITE) READ_ONLY NONSTRICT_READ_WRITE READ_WRITE Modificações frequentesTuesday, August 7, 2012
  88. 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. 89. Como 2nd Level Cache funciona?Tuesday, August 7, 2012
  90. 90. 2nd Level Cache não faz cache das instancias das entidadesTuesday, August 7, 2012
  91. 91. 2nd Level Cache não faz cache das instancias das entidades somente dos valores das propriedadesTuesday, August 7, 2012
  92. 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. 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. 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. 95. 2nd Level Cache não faz cache das associaçõesTuesday, August 7, 2012
  96. 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. 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. 98. Devo cachear todas as minhas entidades?Tuesday, August 7, 2012
  99. 99. Com 2nd Level Cache tudo funciona bem enquanto buscamos por ID... session.load(Issue.class,  17);Tuesday, August 7, 2012
  100. 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. 101. #4 Query CacheTuesday, August 7, 2012
  102. 102. Query Cache faz cache do resultado de uma queryTuesday, August 7, 2012
  103. 103. Configurando Hibernate para usar Query Cache hibernate.properties hibernate.cache.use_query_cache=trueTuesday, August 7, 2012
  104. 104. Query Cache session    .createQuery("from  Issue  where  status  =  ?")    .setString(0,  status)    .setCacheable(true)    .list();  Tuesday, August 7, 2012
  105. 105. modelo conceitual do query cache Query Cache [“from Issue where status = ?”, [“ABERTA”]] -> [17, 19]Tuesday, August 7, 2012
  106. 106. modelo conceitual do query cache Query Cache [“from Issue where status = ?”, [“ABERTA”]] -> [17, 19] Query + Parâmetros IDsTuesday, August 7, 2012
  107. 107. por isso Query Cache SEM 2nd Level Cache não é de muita ajudaTuesday, August 7, 2012
  108. 108. Utilize somente em consultas que são executadas repetidas vezes com os mesmos parâmetrosTuesday, August 7, 2012
  109. 109. Utilize somente em consultas que são executadas repetidas vezes com os mesmos parâmetrosTuesday, August 7, 2012
  110. 110. #5 Select n+1Tuesday, August 7, 2012
  111. 111. o campeão em prejudicar a performance da aplicaçãoTuesday, August 7, 2012
  112. 112. Processando os itens de uma nota NotaFiscal  nf  =  (NotaFiscal)  session.load (NotaFiscal.class,  42); processaItensDaNota(nf);Tuesday, August 7, 2012
  113. 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=42Tuesday, August 7, 2012
  114. 114. Processando os itens de varias notas List<NotaFiscal>  notas  =  dao.listaTudo(); for  (NotaFiscal  nf  :  notas)  {        processaItensDaNota(nf); }Tuesday, August 7, 2012
  115. 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. 116. são muitos hits no banco de dadosTuesday, August 7, 2012
  117. 117. são muitos hits no banco de dados mas podemos resolver isso...Tuesday, August 7, 2012
  118. 118. 3 soluçõesTuesday, August 7, 2012
  119. 119. #1 EAGER ou join- fetchTuesday, August 7, 2012
  120. 120. Utilizando FetchMode=EAGER @Entity class  NotaFiscal  {    …    @OneToMany(fetch=FetchType.EAGER)    List<Item>  itens; }Tuesday, August 7, 2012
  121. 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_idTuesday, August 7, 2012
  122. 122. antes de definir um mapeamento global deste tipo você precisa se perguntar...Tuesday, August 7, 2012
  123. 123. SEMPRE que uma nota é necessária, todos seus itens também são necessários?Tuesday, August 7, 2012
  124. 124. não?Tuesday, August 7, 2012
  125. 125. Utilizando Join Fetch session    .createQuery("from  NotaFiscal  n   left  join  fetch  n.itens")    .list();  Tuesday, August 7, 2012
  126. 126. #2 batch-size nas associaçõesTuesday, August 7, 2012
  127. 127. É o meio termo entre EAGER e LAZYTuesday, August 7, 2012
  128. 128. @BatchSize @Entity class  NotaFiscal  {    …    @OneToMany    @BatchSize(size=10)    List<Item>  itens; }Tuesday, August 7, 2012
  129. 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. 130. @BatchSize também é conhecido como:Tuesday, August 7, 2012
  131. 131. @BatchSize também é conhecido como: otimização de adivinhação cega (blind-guess optimization)Tuesday, August 7, 2012
  132. 132. @BatchSize também é conhecido como: otimização de adivinhação cega (blind-guess optimization) ou seja, é um palpiteTuesday, August 7, 2012
  133. 133. #3 FetchMode SUBSELECTTuesday, August 7, 2012
  134. 134. SUBSELECT @Entity class  NotaFiscal  {    …    @OneToMany    @Fetch(FetchMode.SUBSELECT)    List<Item>  itens; }Tuesday, August 7, 2012
  135. 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
  136. 136. Qual utilizar?Tuesday, August 7, 2012
  137. 137. Qual utilizar? dependeTuesday, August 7, 2012
  138. 138. #6 Processamento em loteTuesday, August 7, 2012
  139. 139. Imagine que temos que importar 100k produtos para o banco de dadosTuesday, August 7, 2012
  140. 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. 141. em ~50k produtos nós receberíamos um OutOfMemoryExceptionTuesday, August 7, 2012
  142. 142. por que?Tuesday, August 7, 2012
  143. 143. Hibernate faz cache de todas as instâncias dos Produtos inseridos na SessionTuesday, August 7, 2012
  144. 144. mas como melhorar?Tuesday, August 7, 2012
  145. 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
  146. 146. evitamos o OutOfMemoryExceptionTuesday, August 7, 2012
  147. 147. evitamos o OutOfMemoryException Mas o processamento ainda continua lento!Tuesday, August 7, 2012
  148. 148. evitamos o OutOfMemoryException Mas o processamento ainda continua lento! Dá pra melhorar?Tuesday, August 7, 2012
  149. 149. JDBC puro?Tuesday, August 7, 2012
  150. 150. JDBC puro? código de maxu! Handerson FrotaTuesday, August 7, 2012
  151. 151. StatelessSessionTuesday, August 7, 2012
  152. 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 eventosTuesday, August 7, 2012
  153. 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. 154. menos consumo de memória e mais rápida!Tuesday, August 7, 2012
  155. 155. dá pra melhorar? Yuri Adams menos consumo de memória e mais rápida!Tuesday, August 7, 2012
  156. 156. hibernate.properties hibernate.jdbc.batch_size=50Tuesday, August 7, 2012
  157. 157. CONCLUSÃOTuesday, August 7, 2012
  158. 158. Foi apenas a ponta o iceberg!Tuesday, August 7, 2012
  159. 159. cada uma destas dicas são simples, mas requerem mais estudoTuesday, August 7, 2012
  160. 160. cada uma destas dicas são simples, mas requerem mais estudo pois depende do projetoTuesday, August 7, 2012
  161. 161. um DBA certamente pode ter ajudar em muitos cenáriosTuesday, August 7, 2012
  162. 162. Hibernate não é seu inimigo, deixem de #mimimiTuesday, August 7, 2012
  163. 163. Rafael Ponte rponte@triadworks.com.brTuesday, August 7, 2012
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×