Vous êtes sur la page 1sur 8

Captulo 19.

Aumentando a performance
19.1. Estratgias de Fetching

qualquer.

Aumentando a performance

19.1.1. Trabalhando com associaes preguiosas (lazy)

Por padro, o Hibernate3 usa busca preguiosa para colees e busca preguiosa com proxy para associaes
de um valor. Esses padres fazem sentido para quase todas as associaes em quase todas a aplicaes.

Veja: se voc setar hibernate.default_batch_fetch_size, O Hibernate ir usar otimizao de carregamento


em lote para o carregamento preguioso(Essa otimizao pode ser tambm habilitada em um nvel mais fino).

tx.commit();
s.close();

Integer accessLevel = (Integer) permissions.get("accounts");

<set name="permissions"
fetch="join">
<key column="userId"/>
<one-to-many class="Permission"/>
</set

<many-to-one name="mother" class="Cat" fetch="join"/>

A estratgia de fetch definida no documento de mapeamento afeta:


recupera via get() ou load()

Recuperaes que acontecem implicitamente quando navegamos por uma associao


Hibernate 3.2 ga

183

O select fetching (o padro) extremamente vunervel para problemas em select N+1 , ento ns iremos querer
habilitar o join fetching no documento de mapeamento:

19.1.2. Personalizando as estratgias de recuperao

Por outro lado, ns geralmente escolhemos join fetching (que no preguiosa por natureza) ao invs de select
fetching em uma transao particular. Ns iremos ver como customizar a estratgia de busca. No Hibernate3,
os mecanismos para escolher a estratgia de fetching so identicos para as associaes simples e para colees.

Alternativamente, ns podemos usar uma coleo ou associao com carga antecipada, especificando
lazy="false" no mapeamento da associao. Porm, a inteno que a inicializao tardia seja usada por quase todas as colees e associaes. Se voc definir muitas associaes com carga antecipada em seu modelo de
objetos, o Hibernate ir precisar carregar o banco de dados inteiro na memria em cada transao!

Como a coleo de permisses no foi inicializada quando a Session foi fechada, a coleo no poder carregar o seu estado. O Hibernate no suporta inicializao tardia ara objetos desconectados. Para resolver isso,
necessrio mover o cdigo que carrega a coleo para antes da transao ser comitada.

// Error!

User u = (User) s.createQuery("from User u where u.name=:userName")


.setString("userName", userName).uniqueResult();
Map permissions = u.getPermissions();

s = sessions.openSession();
Transaction tx = s.beginTransaction();

Uma estratgia de fetching a estratgia que o Hibernate ir usar para buscar objetos associados se a aplicao
precisar navegar pela associao. Estratgias de Fetch podem ser declaradas nos metadados de mapeamento O/
R, ou sobrescritos por uma query HQL ou query com Criteria.

Porm, a busca preguiosa tem um problema que voc precisar saber. Acesso a associaes preguiosas fora do
contexto de uma sesso aberta do Hibernate ir resultar numa exceo. Por exemplo:
JOIN

O Hibernate3 define as seguintes estratgias de fetching:


Join fetching - o Hibernate busca o objeto ou coleo associada no mesmo SELECT, usando um OUTER
Select fetching - um segundo SELECT usado para buscar a entidade ou coleo associada. A menos que voc desabilite lazy fetching especificando lazy="false", esse segundo SELECT ser executado apenas
quando voc acessar a associao.
Subselect fetching - um segundo SELECT ser usado para buscar as colees associadas de todas as entidades
buscadas na query ou fetch anterior. A menos que voc desabilite lazy fetching especificando
, esse segundo SELECT ser executado apenas quando voc acessar a associao.
lazy="false"

Batch fetching - uma opo de otimizao para o Select Fetching O Hibernate busca um lote de instncias
ou entidades usando um nico SELECT, especificando uma lista de primary keys ou foreing keys.
O Hibernate distingue tambm entre:
Immediate fetching - uma associao, coleo ou atributo buscado como ela carregada (Qual SQL usado). No se confuda com eles! Ns usamos fetch para melhorar a performance. Ns podemos usar lazy para
definir um contrato para qual dado sempre disponvel em qualquer instncia desanexada de uma classe
qualquer. imediatamente, quando o pai carregado.
Lazy collection fetching - a coleo buscada quando a aplicao invoca uma operao sobre aquela coleo (Esse o padro para colees)
"Extra-lazy" collection fetching - elementos individuais de uma coleo so acessados do banco de dados
quando preciso. O Hibernate tenta no buscar a coleo inteira dentro da memria ao menos que seja absolutamente preciso. (indicado para colees muito grandes)
Proxy fetching - uma associao de um valor carregada quando um mtodo diferente do getter do identificador invocado sobre o objeto associado.
"No-proxy" fetching - uma associao de um valor carregada quando a varivel da instncia carregada.
Comparada com a proxy fetching, esse mtodo menos preguioso (lazy)(a associao carregada somente
quando o identificador acessada) mas mais transparente, j que no h proxies visveis para a aplicao.
Esse mtodo requer instrumentao de bytecodes em build-time e raramente necessrio.
Lazy attribute fetching - um atributo ou associao de um valor carregada quanto a varavel da instncia
acessada. Esse mtodo requer instrumentao de bytecodes em build-time e raramente necessrio.

182

Ns temos aqui duas noes ortogonais: quando a associao carregada e como ela carregada (Qual SQL
usado). No se confuda com eles! Ns usamos fetch para melhorar a performance. Ns podemos usar lazy para definir um contrato para qual dado sempre disponvel em qualquer instncia desconectada de uma classe
Hibernate 3.2 ga


Criteria

queries

Aumentando a performance

buscas por HQL se buscar por subselect for usado


Independentemente da estratgia de busca que voc usar, o grafo no preguioso definido ser garantidamente
carregado na memria. Note que isso ir resultar em diversos selects imediatos sendo usados em um HQL em
particular.

get()

ou
load()

, simplesmente use uma query

Usualmente no usamos documentos de mapeamento para customizar as buscas. Ao invs disso, ns deixamos
o comportamento padro e sobrescrevemos isso em uma transao em particular, usando left join fetch no
HQL. Isso diz ao Hibernate para buscar a associao inteira no primeiro select, usando um outer join. Na API
de busca Criteria, voc ir usar setFetchMode(FetchMode.JOIN).
Se voc quiser mudar a estratgia de busca usada pelo
, por exemplo:
Criteria
User user = (User) session.createCriteria(User.class)
.setFetchMode("permissions", FetchMode.JOIN)
.add( Restrictions.idEq(userId) )
.uniqueResult();

(Isto o equivalente do Hibernate para o que algumas solues ORM chamam de "plano de busca")
Um meio totalmente diferente de evitar problemas com selects N+1 usar um cache de segundo nvel.
19.1.3. Proxies de associao single-ended

A recuperao tardia para colees implementada usando uma implementao prpria do Hibernate para colees persistentes. Porm, um mecanismo diferente necessrio para comportamento tardio para associaes de
um lado s. A entidade alvo da associao precisa usar um proxy. O Hibernate implementa proxies para inicializao tardia em objetos persistentes usando manipulao de bytecode (via a excelente biblioteca CGLIB).
Por padro, o Hibernate3 gera proxies (na inicializao) para todas as classes persistentes que usem eles para
habilitar recuperaopreguiosa de associaes many-to-one e one-to-one.
O arquivo de mapeamento deve declaram uma interface para usar como interface de proxy para aquela classe,
com o atributo proxy. Por padro, o Hibernate usa uma subclasse dessa classe. Note que a classe a ser usada
via proxy precisa implementar o construtor padro com pelo menos visibilidade de package. Ns recomendamos esse construtor para todas as classes persistentes!

Existe alguns truques que voc deve saber quando extender esse comportamento para classes polimrficas, dessa maneira:
<class name="Cat" proxy="Cat">
......
<subclass name="DomesticCat">
.....
</subclass>
</class>

184

// instantiate a proxy (does not hit the db)


// hit the db to initialize the proxy
// Error!

Primeiramente, instncias de Cat nunca sero convertidas para DomesticCat, mesmo que a instncia em questo seja uma estncia de DomesticCat:
Cat cat = (Cat) session.load(Cat.class, id);
if ( cat.isDomesticCat() ) {
DomesticCat dc = (DomesticCat) cat;
....

Hibernate 3.2 ga

possvel quebrar o proxy ==.

Aumentando a performance

Cat cat = (Cat) session.load(Cat.class, id);


// instantiate a Cat proxy
DomesticCat dc =
(DomesticCat) session.load(DomesticCat.class, id); // acquire new DomesticCat proxy!
System.out.println(cat==dc);
// false

Porm a situao no to ruim como parece. Mesmo quando temos duas referncias para objetos proxies diferentes, a instncia deles ser o mesmo objeto

cat.setWeight(11.0); // hit the db to initialize the proxy


System.out.println( dc.getWeight() ); // 11.0

Terceiro, Voc no pode usar um proxy CGLIB em uma classe final ou com qualquer mtodo final.

Finalmente, se o seu objeto persistente adquirir qualquer recursto durante a instanciao (em inicializadores ou
construtor padro), ento esses recursos sero adquiridos pelo proxy tambm. A classe de proxy uma subclasse da classe persistente.

Esses problemas so todos devido a limitao fundamental do modelo de herana simples do Java. Se voc quiser evitar esse problemas em suas classes persistentes voc deve imeplementar uma interface que declare seus
mtodos de negcio. Voc deve especificar essas interfaces no arquivo de mapeamento. Ex:

<class name="CatImpl" proxy="Cat">


......
<subclass name="DomesticCatImpl" proxy="DomesticCat">
.....
</subclass>
</class>

onde CatImpl implementa a interface Cat e DomesticCatImpl implementa a interface DomesticCat. Ento proxies para instncias de Cat e DomesticCat sero retornadas por load() ou iterate(). (Note que list() geralmente no retorna proxies).

Cat cat = (Cat) session.load(CatImpl.class, catid);


Iterator iter = session.iterate("from CatImpl as cat where cat.name='fritz'");
Cat fritz = (Cat) iter.next();

Relacionamentos so tambm carregados preguiosamente. Isso significa que voc precisa declarar qualquer
propriedade como sendo do tipo Cat, e no CatImpl.

Algumas operaes no requerem inicializao por proxy:

equals(), se a classe persistente no sobrescrever equals()


hashCode(), se a classe persistente no sobrescrever hashCode()
O mtodo getter do identificador

O Hibernate ir detectar classes persistentes que sobrescrevem equals() ou hashCode().

185

Escolhendo lazy="no-proxy" ao invs do padro lazy="proxy", podemos evitar problemas associados com typecasting. Porm, iremos precisar de instrumentao de bytecode em tempo de compilao e todas as operaes
iro resultar em iniciazaes de proxy imediatas.

19.1.4. Inicializando colees e proxies

Hibernate 3.2 ga

Algumas vezes precisamos garantir qie o proxy ou coleo inicializado antes de se fechar a Session. Claro
que sempre podemos forar a inicializao chamando cat.getSex() ou cat.getKittens().size(), por exemplo. Mas isto parece confuso para quem l o cdigo e no conveniente para cdigos genricos.

Ser lanada uma LazyInitializationException se uma coleo no inicializada ou proxy acessado fora do
escopo da Session, isto , quando a entidade que contm a coleo ou tem a referncia ao proxy estiver no estado destachado.

Aumentando a performance

O Hibernate pode fazer uso eficiente de busca em lote, isto , o Hibernate pode carregar diversos proxies no
inicializados se um proxy acessado (ou colees. A busca em lote uma otimizao da estratgia de select
fetching). Existe duas maneiras em que voc pode usar busca em lote: no nvel da classe ou no nvel da coleo.

Aumentando a performance

<class name="Document">
<id name="id">
<generator class="native"/>
</id>
<property name="name" not-null="true" length="50"/>
<property name="summary" not-null="true" length="200" lazy="true"/>

Hibernate 3.2 ga

187

Para habilitar a carga posterior de propriedade, preciso setar o atributo lazy no seu mapeamento de propriedade:

O Hibernate3 suporta a carga posterior de propriedades individuais. Essa tcnica de otimizao tambm conhecida como fetch groups. Veja que isso mais uma funcionalidade de marketing j que na prtica, mais importante otimizao nas leituras dos registros do que na leitura das colunas. Porm, carregar apenas algumas propriedades de uma classe pode ser til em casos extremos, onde tabelas legadas podem ter centenas de colunas e
o modelo de dados no pode ser melhorado.

19.1.7. Usando busca preguiosa de propriedade

Se uma coleo ou proxy simples precisa ser recuperado, o Hibernate carrega todos eles rodando novamente a
query original em um subselect. Isso funciona da mesma maneira que busca em lote, sem carregar tanto.

19.1.6. Usando subselect fetching

A busca em lote de colees particularmente til quando voc tem uma rvore encadeada de items, ex. o tpico padro bill-of-materials (Se bem que um conjunto encadeado ou caminho materializado pode ser uma opo
melhor para rvores com mais leitura)

Com um batch-sizede 8, o Hibernate ir carregar 3, 3, 3, 1 colees em 4 SELECTs. Novamente, o valor do


atributo depende do nmero esperado de colees no inicialiadas em determinada Session.

<class name="Person">
<set name="cats" batch-size="3">
...
</set>
</class>

Voc tambm pode habilitar busca em lote de uma coleo. Por exemplo, se cada Person tem uma coleo lazy
de Cats, e 10 pessoas j esto carregados em uma Sesssion, sero gerados 10 SELECTs ao se iterar todas as pessoas, um para cada chamada de getCats().. Se voc habilitar a busca em lote para a coleo de cats no mapeamento da classe Person, o Hibernate pode fazer uma pr carga das colees:

O Hibernate ir executar agora apenas trs consultas, buscando por vez, 10, 10 e 5 Person.

<class name="Person" batch-size="10">...</class>

batch-size

SELECT()

A recuperao em lote para classes/entidades mais fcil de entender. Imagine que voc tem a seguinte situao em tempo de execuo: Voc tem 25 instncias de Cat carregadas em uma Session, cada Cat tem uma referncia ao seu owner, que da classe Person. A classe Person mapeada com um proxy, lazy="true". Se voc iterar sobre todos os Cat's e chamar getOwner() em cada, o Hibernate ir por padro executar 25 comandos
, para buscar os proxies de owners. Voc pode melhorar esse comportamento especificando um
no mapeamento da classe Person:

Os mtodos estticos Hibernate.initialize() e Hibernate.isInitialized() possibilitam a aplicao uma


maneira conveniente de trabalhar com colees inicializadas preguiosamente e proxies. Hibernair forar a inicializao de um proxy, cat, contanto que a Session esteja ainda aberta.
tem um efeito similar para a coleo de kittens.

Hibernate.initialize( cat.getKittens() )

te.initialize(cat)

Outra opo manter a Session aberta at que todas as colees e proxies necessrios sejam carregados. Em
algumas arquiteturas de aplicaes, particularmente onde o cdigo que acessa os dados usando Hibernate e o
cdigo que usa os dados esto em diferentes camadas da aplicao ou diferentes processos fsicos, ser um problema garantir que a Session esteja aberta quando uma coleo for inicializada. Existem dois caminhos bsicos
para lidar com esse problema:
Em aplicaes web, um filtro servlet pode ser usado para fechar a Session somente no final da requisio
do usurio, j que a renderizao da viso estar completa (o pattern Open Session In View). Claro, que isto
cria a necessidade de um correto manuseio de excees na infraestrutura de sua aplicao. vitalmente importante que a Session esteja fechada e a transao terminada antes de retornar para o usurio, mesmo que
uma exceo ocorra durante a renderizao da view. Veja o Wiki do Hibernate para exemplos do pattern
"Open Session In View"
Em uma aplicao com uma camada de negcios separada, a lgica de negcios deve "preparar" todas as
colees que sero usadas pela camada web antes de retornar. Isto sgnifica que a camada de negcios deve
carregar todos os dados e retorn-los j inicializados para a camada de apresentao. Usualmente a aplicao chama Hibernate.initialize() para cada coleo que ser usada pela camada web (essa chamada de
mtodo deve ocorrer antes da sesso ser fechada ou retornar a coleo usando uma consulta Hibernate com
uma clusula FETCH ou um FetchMode.JOIN na Criteria. Fica muito mais fcil se voc adotar o pattern
Command ao invs do Session Facade.

Voc tambm pode anexar um objeto prevaimente carregado em uma nova Session merge() or lock() antes de acessar colees no inicializadas (ou outros proxies). O Hibernate no faz e certamente no deve isso automaticamente pois isso introduziria semantica em transaes ad hoc.
As vezes voc no quer inicializar uma coleo muito grande, mas precisa de algumas informaes (como o tamanho) ou alguns de seus dados.
Voc pode usar um filtro de coleo para saber seu tamanho sem a inicializar:
( (Integer) s.createFilter( collection, "select count(*)" ).list().get(0) ).intValue()

186

O mtodo createFilter() usado tambm para retornar algus dados de uma coleo eficientemente sem precisar inicializar a coleo inteira:
s.createFilter( lazyCollection, "").setFirstResult(0).setMaxResults(10).list();

19.1.5. Usando busca em lote

Hibernate 3.2 ga

Aumentando a performance

classe Provider

Suporte a
Cluster

sim
(invalidao
de cluster)

Suporta consultas no Cache

sim

Clusterizado sim
sim (clock
(ip multicast), (replicaao) sync req.)
transacional

Clusterizado(ip multicast)

memoria, disco

Tipo

Aumentando a performance

org.hibernate.cache.OSCacheProvider

Cache
OSCache

<property name="text" not-null="true" length="2000" lazy="true"/>


</class>

A carga posterior de propriedades requer instrumentao de bytecode! Se suas classes persistentes no forem
melhoradas, o Hibernate ir ignorar silenciosamente essa configurao e usar busca imediatamente.

org.hibernate.cache.SwarmCacheProvider

/>
(1)

(2)

(3)

Hibernate 3.2 ga

(1)
(2)
(3)

189

Em aplicaes que precisam atualizar os dados, um cache read-write o mais apropriado. Essa estratgia de
cache no deve ser usada se o nivel de isolamento da transao requido for serializable. Se esse cache for usado
em ambeinte JTA, voc tem que dar um nomea para a estratgia especificando a propriedade hiberna-

19.2.3. Strategia: read/write

<class name="eg.Immutable" mutable="false">


<cache usage="read-only"/>
....
</class>

Se sua aplicao precisar ler mas nunca modificar as intancias de classes persistentes, deve ser usado um cache
read-only. Essa a estratgia mais simples e de melhror performance. Inclusive perfeitamente segura para o
uso em cluster.

19.2.2. Strategia: somente leitura

O atributo usage especifica a estratgia de concorrencia do cache.

Outra maneira (prefierivel), voc pode especifcar os elementos <class-cache> e <collection-cache> no arquivo hibernate.cfg.xml.

usage (obrigatrio) especifica a estratgia de caching: transactional, read-write, nonstrict-read-write or read-only


region (opicional, valor default o nome da classe da nome da role de collection ) especifica o nome da regio do cach de segundo nvel
include (opcional, valor default all) non-lazy especifica que as as propriedade de uma entidade mapeada com lazy="true" no sero cacheadas quando o atributo level lazy fetching estiver habilitado

<cache
usage="transactional|read-write|nonstrict-read-write|read-only"
region="RegionName"
include="all|non-lazy"

O elemento <cache> do mapeamento de uma classe ou coleo tem a seguinte forma :

19.2.1. Mapeamento do cache

org.hibernate.cache.TreeCacheProvider

SwarmCache

no HQL.

JBoss TreeCache

Para instrumentao de bytecode, use a seguinte tarefa do Ant:


<target name="instrument" depends="compile">
<taskdef name="instrument" classname="org.hibernate.tool.instrument.InstrumentTask">
<classpath path="${jar.path}"/>
<classpath path="${classes.dir}"/>
<classpath refid="lib.class.path"/>
</taskdef>
<instrument verbose="true">
<fileset dir="${testclasses.dir}/org/hibernate/auction/model">
<include name="*.class"/>
</fileset>
</instrument>
</target>

all properties

Um modo diferente (melhor?) para evitar a leitura desnecessria de colunas, pelo menos para transaes de somente de leitura usar as caractersticas de projeo do HQL ou consultas por Critrios. Isto evita a necessidade de processamento de bytecode em tempo de execuo e certamente uma soluo melhor.
Voc pode forar a carga antecipada da propriedades usando fetch

19.2. O Cache de segundo nvel


Uma Session do Hibernate um cache um de dados persistentes em nivel transacional. possvel configurar
um cluster ou cache a nvel da JVM (nvel SessionFactory)em uma base classe-por-classe e coleopor-coleo. Voc pode at mesmo associar um cache a um cluster. Tenha cuidado. Os cache no esto a par
das mudanas feitas nos dados persistentes por outras aplicaes (embora eles possam ser configurados para
expirar os dados de cached regularmente).

sim

Tipo
memoria

sim
188

Suporta consultas no Cache

memoria, disco

Suporte a
Cluster

Voc tem a opo para dizer ao Hibernate qual implementao de caching ele deve usar especificando o nome
de uma classe que implementa a interface org.hibernate.cache.CacheProvider usando a propriedade hibernate.cache.provider_class. O Hibernate vem com vrias implementaes para integrao com vrios providerss de cache open-source (listados abaixo); Adicionalmente, voc poderia criar sua prprio implementao
como descrito acima. Veja que antes d verso de 3.2 era usado o EhCache como provider de cache padro; isso
no mais o caso a partir de 3.2.

org.hibernate.cache.EhCacheProvider

ider

org.hibernate.cache.HashtableCacheProv

classe Provider

Tabela 19.1. Cache Providers


Cache
Hashtable
(no indicado
para uso em
produo)
EHCache
Hibernate 3.2 ga

Aumentando a performance
te.transaction.manager_lookup_class para obtter uma TransactionManager JTA. Em outros ambientes,
voc deve assegurar que a transao foi completada quando Session.close() ou Session.disconnect() for
chamado. Se voc quiser usar essa estratgia em cluster, voc deve assegurar que a implementa de cache utilizada suporta locking. Os caches que vem junto com o Hibernate no suportam.

Aumentando a performance

Aps isso, quando o flush() chamado, o estado deste objeto ser sincronizado com o banco de dados. Se voc no quizer que esta sincronizao acontea ou se voc estover processando um nmero enorme de objetos e
precisa administrar memria de maneira eficaz, o mtodo evict() pode ser usado para remover o objeto e suas
colees do cache de primeiro-nvel.

ScrollableResult cats = sess.createQuery("from Cat as cat").scroll(); //a huge result set


while ( cats.next() ) {
Cat cat = (Cat) cats.get(0);
doSomethingWithACat(cat);
sess.evict(cat);
}

A Session tambm prov o mtodo contains() para determinar se uma instancia pertence ao cache da sesso.

Para remover completamente todos os objetos do cache da sesso, use Session.clear()

<class name="eg.Cat" .... >


<cache usage="read-write"/>
....
<set name="kittens" ... >
<cache usage="read-write"/>
....
</set>
</class>

19.2.4. Estratgia: nonstrict read/write

Para o cache de segundo-nvel, h mtodos definidos na SessionFactory parar remover o cache de estado de
uma instancia, uma classe inteira, uma instancia de coleo ou uma coleo inteira.

EHCache

Hashtable (no
projetado para uso
em produo)
sim

sim

sim

read-only

sim

sim

sim

sim

nonstrict-read-write

sim

sim

sim

read-write

- l itens do e escreve itens no cache de segundo nvel

- l itens do cache de segundo nvel, mas no escreve no mesmo, exeto a atualizao de da-

CacheMode.NORMAL
CacheMode.GET

dos

CacheMode.PUT

- escreve item no cache de segundo nivel, mas no l do mesmo anulando o efeito de


, e forcando uma atualizao do cach de segundo nvel para todos os

- escreve itens no cache de segundo nvel, mas no l dados do mesmo

CacheMode.REFRESH

hibernate.cache.use_query_cache true

Hibernate 3.2 ga

191

Os result sets de consultas tambm podem ser cacheados. Isto s til para consultas que freqentemente so
executadas com os mesmos parmetros. Para usar o cache de consulta voc tem que habilit-lo primeiro:

19.4. O cach de consultas

hibernate.generate_statistics true
hibernate.cache.use_structured_entries true

Voc precisar habilitar estatsticas, e, opicionalmente, fora o Hibernate ra manter as entradas no cach um
formato mais compreensvel:

Map cacheEntries = sessionFactory.getStatistics()


.getSecondLevelCacheStatistics(regionName)
.getEntries();

Para navegar no conteudo do cache de segundo ou na regiao de consulta do cache, use a API Statistics:

items carregados do bando de dados

hibernate.cache.use_minimal_puts

O CacheMode controla como uma sesso em particular interage com o cache de segundo-nvel.

sessionFactory.evict(Cat.class, catId); //evict a particular Cat


sessionFactory.evict(Cat.class); //evict all Cats
sessionFactory.evictCollection("Cat.kittens", catId); //evict a particular collection of kittens
sessionFactory.evictCollection("Cat.kittens"); //evict all kitten collections

Se a aplicao apenas ocasionalmente precisa atualizar os dados (ie. se for extremamente improvvel que duas
transaes tentem atualizar o mesmo item simultaneamente) e um rgido isolamento de transao no for requerido, um cache nonstrict-read-write pode ser apropriado. Se o cache for usado em um ambiente JTA, voc
tem que especificar hibernate.transaction.manager_lookup_class. Em outros ambientes, voc deve assegurar que a transao esteja completa quando Session.close() ou Session.disconnect() for chamado.
19.2.5. Estratgia: transactional

A estratgia de cache transactional prov um completo suporte para provedores de cache transacionais como
JBoss TreeCache. Tal cache s pode ser usado em um ambiente JTA e voc tem que especificar hiberna.

te.transaction.manager_lookup_class

OSCache
sim

sim

transactional

Nenhum dos provedores de cache suporta todas as estratgias de concorrencia de cache. A seguinte tabela mostra quais provedores so compatveis com que estratgias de concorrencia.

Tabela 19.2. Suporte a estratgia de concorrencia em cache

SwarmCache
sim

Cache

JBoss TreeCache

19.3. Administrando os caches

190

Sempre que voc passa um objeto para save(), update() ou saveOrUpdate() e sempre que voc recupera um
objeto usando load(), get(), list(), iterate() ou scroll(), esse objeto acrescentado no cache interno da
..
Session

Hibernate 3.2 ga

Aumentando a performance

Aumentando a performance
bags

Todas as colees indexadas (maps, lists, arrays) tm uma chave primria formadas pelas colunas <key> e
<index>. Nestes casos as atualizaes de coleo so extremamente eficientes - a chave primria pode ser indexada eficazmente e uma linha em particular pode ser localizada eficazmente quando o Hibernate tenta atualizala ou apaga-la.

Hibernate 3.2 ga

193

Antes que voc condene os bag para sempre, h um caso particular no qual os bags (e tambm lists) so muito
mais performticos que os sets. Para uma coleo com inverse="true" (o idioma fr relacionamento padro

19.5.3. Bags e lists so as colees inversas mais eficientes

Sem dvida, em modelos Hibernate de domnio bem definidos, ns normalmente vemos que a maioria das colees so na realidade associaes um-para-muitos com inverse="true". Para estas associaes, a atualizao
controlada pelo lado da associao muitos-para-um, e as consideraes de desempenho na atualizao de coleo simplesmente no se aplicam.

Depois de observar que os arrays no podem ser lazy, ns concluiramos que lists, maps e idbags so mais performticos para a maioria dos tipos colees(no inversas), com os conjuntos (sets) vindo logo atrs. Espera-se
que os sets sejam o o tipo mais comum de coleo nas aplicaes Hibernate. Isto se deve ao fato de que a semntica do "set" muito parecida com o modelo relational.

H, discutivelmente, mais uma vantagem que as colees indexadas tem sobre sobre outros conjuntos para associaes muitos-para-muitos ou colees dos valores. Por causa da estrutura do Set, o Hibernate nem sequer
atualiza uma linha com UPDATE, quando um elemento " alterado". As mudanas em um Set sempre so feitas
atravs de INSERT e DELETE (de linhs individuais). Mais uma vez, estas regras no se aplicam a associaes umpara-muitos.

A partir da discusso anterior, deve ficar claro que colees indexadas e sets (normalmente) permitem peraes
mais eficiente em termos de adio, remoo e atualizao elementos.

19.5.2. Lists, maps, idbags e sets so as colees mais eficientes de se


atualizar

Veja que para uma associao um-para-muitos , a "chave primria" pode no ser a chave primria fsica da tabela do banco de dados - mas at mesmo neste caso, a classificao anterior ainda til. (Ainda reflete como o
Hibernate "localiza" linhas individuais da coleo.)

Os Bags so o pior caso. Considerando que um bag permite que valores de elementos duplicadose no tem nenhuma coluna ndice, nenhuma chave primria pode ser definida. O Hibernate no tem nenhum modo de distinguir linhas duplicadas. O Hibernate soluciona este problema removendo (em um nico DELETE) completamente
e recriando a coleo sempre que ele safre alguma mudan. Isto pode ser muito ineficiente.

Os mapeamentos <idbag> definem uma chave substituta, assim eles sempre so muito eficientes a atualizao.
Na realidade, esse o melhor caso.

Os conjuntos (sets) tm uma chave primria que consiste de <key> e colunas de elemento. Isto pode ser menos
eficiente para alguns tipos de elementos de coleo, particularmente elementos compostos ou textos grandes ou
campos binrios; o banco de dados pode no ser capaz de indexar uma chave primria complexa de modo eficiente. Por outro lado, em associaes um-para-muitos ou muitos-para-muitos, particularmente no caso de identificadores sintticos, provvel que sejam eficientes. (Nota: se voc quer que o SchemaExport crie de fato uma
chave primria de um <set> , voc tem que declarar todas as colunas como not-null="true".)

Esta configurao causa a criao de duas regies novas no cach - um contendo os result set de consultas
(org.hibernate.cache.StandardQueryCache), o outra contendo timestamps das ultimas atualizaes para tabelas consultaveis (org.hibernate.cache.UpdateTimestampsCache). Veja que o cach de consulta no coloca em
cach o estado das entidades que esto no result set; ele coloca em cach apenas os valores dos identificadores
e resultados de tipo de valor. Assim cach de consulta sempre deve sempre ser usado junto com o cach de segundo nvel.
A maioria das consultas no se beneficia de tratamento de cach, assim por padro as consultas no so tratadas
no cach. Para habilitar o tratamento de cach para consultas,chame Query.setCacheable(true). Esta chamada permite a consulta recuperar resultados existente no cach ou acrescentar seus resultados no cach quando
for executada.
.

Se voc quiser um controle bem granulado sobre aspolticas de expirao do cach de consultas, voc pode especificar uma regio do cach nomeada para uma consulta emm particular chamando
Query.setCacheRegion()
List blogs = sess.createQuery("from Blog blog where blog.blogger = :blogger")
.setEntity("blogger", blogger)
.setMaxResults(15)
.setCacheable(true)
.setCacheRegion("frontpages")
.list();

Se a consulta deve forar uma atualizao de sua regio no cach de consulta, voc dever chamar
Query.setCacheMode(CacheMode.REFRESH). Isto particularmente til em casos onde os dados subjacentes podem ter sido atualizados por um processo separado (i.e., no modificados atravs do Hibernate) e permite a
aplicao uma atualizao seletiva dos result sets de uma consulta em particular. Esta uma alternativa mais
eficiente do que a limpeza de uma regio do cach de consultas via SessionFactory.evictQueries().

19.5. Entendendo a performance de colees


Ns j gastamos algum tempo falando sobre colees. Nesta seo ns veremos com mais detalhes um par mais
assuntos sobre como colees se comportam em tempo de execuo.
19.5.1. Taxonomania

O Hibernate define trs tipos bsicos de colees:


colees de valores
associaes um para muitas
associaes muitas para muitas

192

Esta classificao distingue as vrias tabelas e foreing key mas no nos diz nada do que ns precisamos saber
sobre o modelo de relational. Entender completamente estrutura relational e as caractersticas de desempenho,
ns tambm temos que considerar a estrutura da chave primria que usada pelo Hibernate para atualizar ou
apagar linhas na coleo. Isto sugere a seguinte classificao :
colees indexadas
sets
Hibernate 3.2 ga

Aumentando a performance
um-para-muitos, por exemplo) ns podemos acrescentar elementos a uma bag ou list sem precisar inicializar
(recupear) os elementos da bag! Isso se deveao fato que Collection.add() ou Collection.addAll() sempre
tm que devolver true para uma bag ou List (ao contrrio de Set). Isto pode fazer o seguinte cdigo comum
funcionar muito mais rpido.
Parent p = (Parent) sess.load(Parent.class, id);
Child c = new Child();
c.setParent(p);
p.getChildren().add(c); //no need to fetch the collection!
sess.flush();

19.5.4. Deletando tudo de uma vez

Ocasionalmente, apagar os elementos de coleo um por um pode ser extremamente ineficiente. O Hibernate
no completamente estpido, e sabe que no deve fazer isso, no caso de uma coleo ser lima (se voc tiver
executado list.clear(), por exemplo). Neste caso, o Hibernate executar um simples DELETE e pronto!
Suponha que ns acrescentamos um nico elemento a uma coleo de tamanho vinte e ento tentarmos remover
dois elementos. O Hibernate emitir uma declaraoINSERT e duas declaraes DELETE (a menos que a coleo
seja uma bag). Isto certamente o desejado.
Porm, suponha que se ns removermos dezoito elementos, deixando dois e ento adicionarmos trs elementos
novos. Existem duas formas possveis de se proceder
deletar as dezoito linhas uma por uma eento inserir as trs linhas
remover toda a coleo ( em um SQL DELETE) e inserir todas os cinco elementos atuais (um por um)
O Hibernate no inteligente o bastante para saber que a segunda opo provavelmente a mais rpida neste
caso. (E provavelmente seria indesejvel que o Hibernate fosse to inteligente; tais comportamentos poderiam
confundir as trigger do banco de dados , etc.)
Felizmente, voc pode forar este comportamento (ie. a segunda estratgia) a qualquer momento descartando
(ie. desreferenciando) a coleo original e criando uma nova coleo com todos os elementos atuais instancidos. Isto pode ser muito til e poderoso de vez em quando .
Claro que, a deleo com apenas um comando no se apliqua a colees mapeadas com inverse="true".

19.6. Monitorando o desempenho


A Otimizao no tem muito uso sem o monitoramento e o acesso a nmeros de desempenho. O Hibernate
prov uma grande gama de informaes sobre suas operaes internas. Estatsticas no Hibernate esto disponvis atravs da SessionFactory.
19.6.1. Monitorando a SessionFactory

Voc pode acessar as mtricas da SessionFactory de dois modos. Sua primeira opo chamar sessionFace ler ou exibir as Statistics voc mesmo.

tory.getStatistics()

194

O Hibernate tambm pode usar a JMX para publicar mtrica se voc habilitar o MBean StatisticsService .
Voc pode habilitar um nico MBean para todos seu SessionFactory ou um por fbrica. Veja o cdigo seguinte para exemplos de uma configurao mais detalhada:
Hibernate 3.2 ga

Aumentando a performance

// MBean service registration for a specific SessionFactory


Hashtable tb = new Hashtable();
tb.put("type", "statistics");
tb.put("sessionFactory", "myFinancialApp");
ObjectName on = new ObjectName("hibernate", tb); // MBean object name

StatisticsService stats = new StatisticsService(); // MBean implementation


stats.setSessionFactory(sessionFactory); // Bind the stats to a SessionFactory
server.registerMBean(stats, on); // Register the Mbean on the server

// MBean service registration for all SessionFactory's


Hashtable tb = new Hashtable();
tb.put("type", "statistics");
tb.put("sessionFactory", "all");
ObjectName on = new ObjectName("hibernate", tb); // MBean object name

StatisticsService stats = new StatisticsService(); // MBean implementation


server.registerMBean(stats, on); // Register the MBean on the server

ou

hibernateStatsBe-

TODO: Isto no faz sentido: No primeiro caso, ns recuperamos e usamos o MBean diretamente. No segundo,
temos que passar o nome JNDI em que a fbrica de sesso est publicada antes de poder usar-la. Use hiberna-

teStatsBean.setSessionFactoryJNDIName("my/JNDI/Name")

Voc pode (des)ativar o monitorando para uma SessionFactory

via configurao: set hibernate.generate_statistics para false

sf.getStatistics().setStatisticsEnabled(true)
an.setStatisticsEnabled(true)

em tempo de execuo:

As estatsticas podem ser resetadas via programao usando o mtodo clear(). Um resumo pode ser enviado a
um logger (nvel info) usando o o mtodo logSummary().
19.6.2. Mtricas

O Hibernate prov um grande nmero de mtricas, de informaes bsicas at informaes especializadas pertinente smente a certos cenrios. As mtrics disponveis so descritas na interface da API Statistics , em
trs categorias:

Mtricas relacionadas ao uso geral da Session, como o nmero de sesses abertas, conexes de JDBC recuperadas, etc.

Mtricas relacionadas as entidades, colees, consultas , e cachs com um todo (tambm conhecidas como
mtrica global),

Mtrica detalhadas relacionadas a uma entidade em particular, coleo, consulta ou regio do cach.

Por examplo, voc pode verificar o acesso, as perdas e a media de entidades, colees e consultas, e o tempo
mdio usados pelas consultas. Lembre-se que o nmero de milissegundos est sujeito ao arredondamento do Java. O Hibernate amarrado preciso de JVM, em algumas plataformas essa preciso pode ser limitada a preciso de 10 segundos.

195

So usados getters simples para acessar as mtricas globais (i.e. no referentes a uma entidade particular, coleo, regio do cache, etc.). Voc pode acessar o mtrica de uma entidade em particular, coleo ou regio do
cach atravs de seu nome, por representao HQL ou SQL para consultas. Por favor verifique as API do JavaHibernate 3.2 ga

Aumentando a performance
doc sobre Statistics, EntityStatistics, CollectionStatistics, SecondLevelCacheStatistics, e QuerySpara mais informaes. Os cdigo seguintes mostram um exemplo simples:

tatistics
Statistics stats = HibernateUtil.sessionFactory.getStatistics();

);

double queryCacheHitCount = stats.getQueryCacheHitCount();


double queryCacheMissCount = stats.getQueryCacheMissCount();
double queryCacheHitRatio =
queryCacheHitCount / (queryCacheHitCount + queryCacheMissCount);
log.info("Query Hit ratio:" + queryCacheHitRatio);
EntityStatistics entityStats =
stats.getEntityStatistics( Cat.class.getName() );
long changes =
entityStats.getInsertCount()
+ entityStats.getUpdateCount()
+ entityStats.getDeleteCount();
log.info(Cat.class.getName() + " changed " + changes + "times"

196

Para trabalhar com todas as entidades, colees, consultas e regies do cach, voc pode recuperar a lista de nomes de entidades, colees, e regies do cach, com os seguintes mtodos : getQueries(), getEntityNames(),
, e getSecondLevelCacheRegionNames().
getCollectionRoleNames()

Hibernate 3.2 ga