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.
Palestra ministrada no evento COALTI 2014 a convite do ALJUG (Grupo de usuários Java de Alagoas).
31. mas nem todos dão a devida atenção...
até perceberem a app engasgando
32. mas nem todos dão a devida atenção...
até perceberem a app engasgando
ou até receberem um
33. 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
34. 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
!
!
!
35. 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
!
!
36. 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
!
!
42. INFO DriverManagerConnectionProvider:64 - Using Hibernate built-in
connection pool (not for production use!)!
INFO DriverManagerConnectionProvider:65 - Hibernate connection pool
size: 20!
43. 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!
56. Percorrendo os itens de uma nota
NotaFiscal
nf
=
(NotaFiscal)
session.load(NotaFiscal.class,
42);
List<Item>
itens
=
nf.getItens();
57. Hibernate executa 2 selects
NotaFiscal
nf
=
(NotaFiscal)
session.load(NotaFiscal.class,
42);
select nf.* from NotaFiscal nf
where nf.id=42
select i.* from Item i
where i.nota_fiscal_id=42
List<Item>
itens
=
nf.getItens();
58. 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());
59. mas ao ler os itens da nota
Session
session
=
sessionFactory.openSession();
!
NotaFiscal
nf
=
(NotaFiscal)
session.load(NotaFiscal.
session.close();
!
List<Item>
itens
=
nf.getItens();
System.out.println(
itens.size());
org.hibernate.LazyInitializationException:
failed to lazily initialize a collection -
no session or session was closed.
109. Com 2nd Level Cache tudo funciona bem
enquanto buscamos por ID...
session.load(Bug.class,
17);
110. Com 2nd Level Cache tudo funciona bem
enquanto buscamos por ID...
session.load(Bug.class,
17);
...mas e quando precisamos de uma
consulta um pouco diferente?
session
.createQuery("from
Bug
where
status
=
?")
.setString(0,"ABERTO")
.list();
121. o campeão em prejudicar
a performance da
aplicação
122. Processando os itens de uma nota
NotaFiscal
nf
=
(NotaFiscal)
session.load(NotaFiscal.class,
42);
processaItensDaNota(nf);
123. Hibernate executa 2 selects
NotaFiscal
nf
=
(NotaFiscal)
session.load(NotaFiscal.class,
42);
select nf.* from NotaFiscal nf
where nf.id=42
select i.* from Item i
where i.nota_fiscal_id=42
processaItensDaNota(nf);
124. List<NotaFiscal>
notas
=
dao.listaTudo();
for
(NotaFiscal
nf
:
notas)
{
processaItensDaNota(nf);
}
Processando os itens de varias notas
125. Hibernate executa n+1 selects
List<NotaFiscal>
notas
=
dao.listaTudo();
select nf.* from NotaFiscal 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=?
...
for
(NotaFiscal
nf
:
notas)
{
processaItensDaNota(nf);
}
145. Hibernate executa 2 selects
List<NotaFiscal>
notas
=
dao.listaTudo();
select nf.* from NotaFiscal nf
select i.* from Item i where
i.nota_fiscal_id in (select nf.id from
NotaFiscal nf)
for
(NotaFiscal
nf
:
notas)
{
processaItensDaNota(nf);
}
162. API mais baixo nível
sem 1st Level Cache
próxima ao jdbc
sem 2nd Level Cache
mapeamento básico
StatelessSession
sem dirty-checking
sem cascade
Collections são ignorados
sem modelo de
eventos sem interceptors
163. 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();