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 Disturbing the Mind 2014 do Instituto Atlântico (IA).
29. mas nem todos dão a devida atenção...
até perceberem a app engasgando
30. mas nem todos dão a devida atenção...
até perceberem a app engasgando
ou até receberem um
31. 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
32. daí percebem que não configuraram o
o pool do Hibernate
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.properties
33. daí percebem que não configuraram o
o pool do Hibernate
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
!
!
hibernate.properties
34. daí percebem que não configuraram o
o pool do Hibernate
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
!
!
hibernate.properties
40. INFO DriverManagerConnectionProvider:64 - Using Hibernate built-in
connection pool (not for production use!)!
INFO DriverManagerConnectionProvider:65 - Hibernate connection pool
size: 20!
41. INFO DriverManagerConnectionProvider:64 - Using Hibernate built-in
connection pool (not for production use!)!
INFO DriverManagerConnectionProvider:65 - Hibernate connection pool
size: 20!
notforproductionuse!
54. NotaFiscal
nf
=
(NotaFiscal)
session.load(NotaFiscal.class,
42);
!
List<Item>
itens
=
nf.getItens();
Percorrendo os itens de uma nota
55. select nf.* from NotaFiscal nf
where nf.id=42
select i.* from Item i
where i.nota_fiscal_id=42
Hibernate executa 2 selects
NotaFiscal
nf
=
(NotaFiscal)
session.load(NotaFiscal.class,
42);
List<Item>
itens
=
nf.getItens();
56. 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());
a session do Hibernate foi fechada
57. Session
session
=
sessionFactory.openSession();
!
NotaFiscal
nf
=
(NotaFiscal)
session.load(NotaFiscal.
session.close();
!
List<Item>
itens
=
nf.getItens();
System.out.println(
itens.size());
mas ao ler os itens da nota
org.hibernate.LazyInitializationException:
failed to lazily initialize a collection -
no session or session was closed.
108. Com 2nd Level Cache tudo funciona bem
enquanto buscamos por ID...
session.load(Bug.class,
17);
109. Com 2nd Level Cache tudo funciona bem
enquanto buscamos por ID...
...mas e quando precisamos de uma
consulta um pouco diferente?
session.load(Bug.class,
17);
session
.createQuery("from
Bug
where
status
=
?")
.setString(0,"ABERTO")
.list();
120. o campeão em prejudicar
a performance da
aplicação
121. NotaFiscal
nf
=
(NotaFiscal)
session.load(NotaFiscal.class,
42);
processaItensDaNota(nf);
Processando os itens de uma nota
122. select nf.* from NotaFiscal nf
where nf.id=42
select i.* from Item i
where i.nota_fiscal_id=42
Hibernate executa 2 selects
NotaFiscal
nf
=
(NotaFiscal)
session.load(NotaFiscal.class,
42);
processaItensDaNota(nf);
123. List<NotaFiscal>
notas
=
dao.listaTudo();
for
(NotaFiscal
nf
:
notas)
{
processaItensDaNota(nf);
}
Processando os itens de varias notas
124. 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=?
...
Hibernate executa n+1 selects
List<NotaFiscal>
notas
=
dao.listaTudo();
for
(NotaFiscal
nf
:
notas)
{
processaItensDaNota(nf);
}
144. select nf.* from NotaFiscal nf
select i.* from Item i where
i.nota_fiscal_id in (select nf.id from
NotaFiscal nf)
Hibernate executa 2 selects
List<NotaFiscal>
notas
=
dao.listaTudo();
for
(NotaFiscal
nf
:
notas)
{
processaItensDaNota(nf);
}
161. StatelessSession
sem 1st Level Cache
sem 2nd Level Cache
sem dirty-checking
sem cascade
Collections são ignorados
sem modelo de
eventos
sem interceptors
próxima ao jdbc
API mais baixo nível
mapeamento básico
162. !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();