Cache Hibernate

48 respostas
J2Alex

Tem como habilitar cache para um relacionamento one-to-one com chave estrangeira?

48 Respostas

Mauricio_Linhares

Dá pra botar lazy true nesse tipo de relacionamento?

J2Alex

?

Paulo_Silveira

da para habilitar lazy sim! apesar do default de relacao com ponta One ser eager.

sobre o second level cache, tasca um @Cache nessa relacao, ta resolvido.

J2Alex

Olá Paulo,

Quanto ao Lazy, não fuciona, ao menos quando eu uso HQL… com critéria acredito que eu consiga ter um controle maior…

Já a questão do cache… realmente não está funcionando. E já li algumas referências na net (google) que dizem que isso não é possível (mas acho que deveria ser). Tem alguma sugestão? :roll:

Será que eu estou marcando bobeira em alguma coisa…

Grato

J2Alex

Paulo, eu de novo…

Se eu tento colocar um cache pra relação one-to-one eu recebo a seguinte excessão:

... invalid mapping
...

SaxParseException: O conteúdo do tipo de elemento "one-to-one" deve corresponder a "(meta*|formula*)"

O que leva a crer que não é possível usar cache pra esse tipo de relação.

No lazy só são possíveis os valores: false, proxy e no-proxy.

Paulo_Silveira

Oi Alex

Nao sei como hbm, mas com anotacoes um simples @OneToOne(fetch=FetchType.LAZY) funciona. Entao deve ter sim como fazer no hbm. Que hibernate voce ta usando? Voce nao ta fazendo “fetch” no HQL neh?

Bem, eu nunca fiz cache de uma relacao que a ponta era One do outro lado, mas nao imagino um motivo pelo qual nao devesse funcionar. Manda os links que voce achou pra gente

Mauricio_Linhares

Rapaz, se dá pra defirnir ela como “lazy=true” ele vai ser carregado do cache da classe assim que alguém tentar acessar a propriedade pela primeira vez, você não precisa habilitar o cache para o relacionamento.

Provavelmente não deve ser possível fazer cache nesse tipo de relação exatamente por isso, ele vai sempre pegar no cache da classe já que tá fazendo o lazy-load de qualquer jeito.

Paulo_Silveira

Mauricio, nao eh bem assim

Cache de relacionamentos funciona como o cache de Queries: ele guarda os IDs. Entao se o livro 7 tem o autor 5 como relacionamento, com cache de relacionamento e lazu esse numero 5 ficaria anotado em algum canto. A dynamic proxy pendurada no getAutor() ja devolve um proxy para levantar o Autor de id 5, sem ter de consultar o banco para ver quem esta relacionado com esse Livro. Pelo menos eh assim para o many. Realmente nao me parece muito util para o One na outra ponta.

J2Alex

O meu problema é o seguinte: eu tenho uma tabela A e uma tabela B que possuem um relacionamento one-to-one de um lado e may-to-one do outro, pois tenho um relacionamento com chave estrangeira.

A questão é que se eu chamo a tabela A (“from A where id = 1”), a tabela B vem junto… eu queria evitar esse comportamento, pois o modelo é complexo, NÃO pode ser mudado e essa característica vai prejudicar o desempenho… eu realmente não preciso da tabela B (lazy=true) na maioria dos casos e em outros casos os dados da tabela B poderiam muito bem estar em cache.

Não posso usar anotações, a solução tem que ser no hbm mesmo.

Paulo, não consegui achar o link que eu tinha lido antes… :frowning:

T

Não faz muito sentido você fazer cache de algo que va mudar constantemente, é legal habilitar cache de segundo nível quando você possui uma coleção de objetos que muito raramente ira ser alterada, assim o ganho de performance sera perceptivel.

robertouba

Estou com um problema de Cache!
Bom, minha aplicação está rodando localmente e em outro servidor, ambos usando do mesmo banco de dados, entretanto, se eu altero um dado local, quando vou receber ele remoto, parece não estar editado, mas se eu fizer um restart do server, ele lê corretamente, portanto, gostaria de saber como desativar o cache do hibernate para algumas classes.

Valew!

yorgan

Bom, se o problema for com um objeto, você pode fazer assim:

objeto = this.session.refresh(objeto);

[]'s
Daniel

robertouba

isso?

@SuppressWarnings("unchecked")
	public List<Filial> listar() {
		this.session.refresh(Filial.class); 
		return this.session.createCriteria(Filial.class).list();
	}
Lucas_Cavalcanti

você chegou a configurar cache de 2o nível?

robertouba

você diz

<property name="cache.use_second_level_cache">rrue</property>

não utilizei nada disso!

Lucas_Cavalcanti

então a menos que você esteja segurando a instância da entidade durante várias requisições, e deixando a session/entityManager aberto, não é cache do hibernate.

se você está segurando a instância com a session fechada, basta fazer o session.refresh como o yorgan falou

robertouba

Dessa maneira?

@SuppressWarnings("unchecked") public List<Filial> listar() { this.session.refresh(Filial.class); return this.session.createCriteria(Filial.class).list(); }

Lucas_Cavalcanti

não…

vc chama esse método listar toda hora? ou vc guarda o resultado dele por bastante tempo?

robertouba

Não chamo toda hora não, mas, o que acontece é… se eu alterar algo, o outro local deve saber se foi modificado ou não, sem precisar de um “refresh”… pois não estaremos acessando apenas de um lugar!

Lucas_Cavalcanti

toda vez que esse método for chamado, vai ser retornada a última versão do banco de dados, mesmo sem o refresh

robertouba

Como resolver isso?

Lucas_Cavalcanti

faça o seguinte:

  • mude uma filial em um sistema
  • liste as filiais no outro sistema (usando esse método!)

e vice-versa.

Isso funciona?

outra coisa: qdo vc muda as filiais em um sistema, vc faz isso dentro de uma transação? ou seja, está indo de verdade pro banco?

robertouba
public void edit(Filial filial) {
		Transaction tx = session.beginTransaction();
		session.update(filial);
		tx.commit();
	}

	@SuppressWarnings("unchecked")
	public List<Filial> listar() {
		return this.session.createCriteria(Filial.class).list();
	}

Bom, está ai, updating de uma filial... Só não entendi ainda como fazer a parte do refresh! kkkkk
LEIGO! kkk

Lucas_Cavalcanti

esquece o refresh, não precisa dele.

se as duas aplicação estão usando o mesmo banco mesmo, deveria funcionar

robertouba

Bom fiz o teste… Adicionei localmente dois registros.
Fui no MySQL e dei select direto na base, estão inseridos.
Mas no servidor remoto não consta os dois registros…
Adicionei um novo registro no servidor remoto… então ele leu os 2 registros.

Portanto, está em cache, e preciso fazer com que as informações fiquem sincronizadas…
Pensei em Flush

session.flush() o que acha?

Lucas_Cavalcanti

não é cache…

pode ser cache da página, não?

o servidor remoto está com a mesma aplicação?

robertouba

exatamente a mesma aplicação, não é cash pois eu entrei na página pela primeira vez… e não reiniciei o tomcat! ou seja, continua com as mesmas informações, entretanto quando ele faz o commit, então ele carrega os dados.

Lucas_Cavalcanti

bom, se vc não configurou o cache de segundo nível, a única explicação é você estar com uma mesma session aberta pra várias requisições, é isso?

robertouba

Claro, isso pode ser sim… Bom fiz o seguinte:

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

import org.hibernate.SessionFactory;
import org.hibernate.cfg.AnnotationConfiguration;

import br.com.caelum.vraptor.ioc.ApplicationScoped;
import br.com.caelum.vraptor.ioc.Component;
import br.com.caelum.vraptor.ioc.ComponentFactory;

@Component
@ApplicationScoped
public class CreateSessionFactory implements ComponentFactory<SessionFactory> {

	private SessionFactory factory;

	@PostConstruct
	public void abre() {
		AnnotationConfiguration configuration = new AnnotationConfiguration();
		configuration.configure();
		this.factory = configuration.buildSessionFactory();
	}

	public SessionFactory getInstance() {
		return factory;
	}

	@PreDestroy
	public void fecha() {
		this.factory.close();
	}

}
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

import org.hibernate.Session;
import org.hibernate.SessionFactory;

import br.com.caelum.vraptor.ioc.Component;
import br.com.caelum.vraptor.ioc.ComponentFactory;

@Component
public class CreateSession implements ComponentFactory<Session> {

	private final SessionFactory factory;
	private Session session;

	public CreateSession(SessionFactory factory) {
		this.factory = factory;
	}

	@PostConstruct
	public void abre() {
		this.session = factory.openSession();
		//this.session.setFlushMode(FlushMode.COMMIT);
		//this.session.setCacheMode(CacheMode.REFRESH);
	}

	public Session getInstance() {
		return this.session;
	}

	@PreDestroy
	public void fecha() {
		this.session.close();
	}

}
Lucas_Cavalcanti

isso é uma session por request… não deveria ter cache

robertouba

Agora você vem falar pra mim!?
Eu sou Leigo no negóciooooooo jkkkkkk

Então, pensei no flush(), o que você acha?

Lucas_Cavalcanti

se você comitou a transação já deveria ir pro banco de dados automaticamente, não precisa do flush…

habilita o show_sql e vê se as selects estão sendo feitas.

no hibernate.cfg.xml, coloque:

<property name="hibernate.show_sql" value="true" />
<property name="hibernate.format_sql" value="true" />

e veja em que momento os selects/inserts estão sendo feitos. daí vc tem uma idéia melhor se precisa fazer o flush ou não

robertouba

Bom, na verdade sempre deixo isso ligado, gosto de ver os selects e inserts sempre…
Está fazendo select a cada requisição, sim… entretanto, verifiquei no banco, e está gravando, e não aparece, cash de página, não pode ser, testei em browsers diferentes… portanto, CACHE kkkk
Meu, realmente não sei o que fazer agora, estou sem saber por onde começar

Lucas_Cavalcanti

se está aparecendo os selects a cada request NÃO é cache, pelo menos não do lado da aplicação… talvez seja algo do banco de dados…

qual você está usando?

robertouba

MySQL 5…
Mas se ele está no banco as informaçlões já estão salvas no banco não pode ser do banco isso

Lucas_Cavalcanti

o banco está em qual máquina? na local ou na remota?
as configurações do banco estão como localhost ou com o ip da máquina?

robertouba

Estão como URL mysql.tal.com.
não estão local, estão remotas.

Lucas_Cavalcanti

posta aqui o seu hibernate.cfg.xml (sem a senha do banco e coisas do tipo) das duas aplicações

robertouba
&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
                                         "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"&gt;
&lt;hibernate-configuration&gt;
	&lt;session-factory&gt;
		&lt;property name="hibernate.connection.driver_class"&gt;com.mysql.jdbc.Driver&lt;/property&gt;
		&lt;property name="hibernate.connection.url"&gt;jdbc:mysql://mysql.quimiflex.net.br/database&lt;/property&gt;
		&lt;property name="hibernate.connection.username"&gt;user&lt;/property&gt;
		&lt;property name="hibernate.connection.password"&gt;password&lt;/property&gt;
		&lt;property name="hibernate.dialect"&gt;org.hibernate.dialect.MySQLDialect&lt;/property&gt;
		&lt;property name="show_sql"&gt;true&lt;/property&gt;

		&lt;mapping class="br.com.rhfactor.quimiflex.entidades.Categoria" /&gt;
		&lt;mapping class="br.com.rhfactor.quimiflex.entidades.Item" /&gt;

	&lt;/session-factory&gt;
&lt;/hibernate-configuration&gt;
Lucas_Cavalcanti

troque o dialect para:

org.hibernate.dialect.MySQL5InnoDBDialect
robertouba

Pronto… feito, novamente…
Iniciei o server local, depois o server remoto.
No server remoto adicionei um registro no banco, OK, perfeito.
Então fui na minha página de listar local, nada do registro, fui em adicionar um novo registro (local), adicionei, e apareceu no listar os 2 registros perfeitamente.

Lucas_Cavalcanti

se você tiver liberdade pra isso, apague a database do projeto, e deixe o hibernate criar de novo.

para isso, coloque a propriedade:

<property name="hibernate.hbm2ddl.auto" value="update" />

se não tiver liberdade, teste com uma outra database e veja se funciona

robertouba

Portanto está fazendo uma select somente depois de um comit, correto?

Lucas_Cavalcanti

não sei, aparece o select depois do insert no log? ou aparece toda vez que você executa a lista?

robertouba

Bom, quando executa a lista (chamando a página de listar)

Hibernate: select this_.id as id17_0_, this_.nome as nome17_0_, this_.sigla as sigla17_0_ from UnidadeMedida this_

Mas novamente, fui direto no banco e adicionei um dado, fiz comit no banco e nada, continua fazendo select e não lendo os dados... Dropei todas as tabelas, e coloquei no hibernate.cfg.xml:

&lt;property name="hibernate.dialect"&gt;org.hibernate.dialect.MySQL5InnoDBDialect&lt;/property&gt;
		&lt;property name="show_sql"&gt;true&lt;/property&gt;
		&lt;property name="hibernate.format_sql"&gt;true&lt;/property&gt;
		
		&lt;property name="hibernate.hbm2ddl.auto"&gt;update&lt;/property&gt;

Mas do mesmo jeito não resolveu.

Lucas_Cavalcanti

cara, não sei o que pode ser… se ele imprime o select no console, quer dizer que ele foi no banco… só se o banco está respondendo o select antigo por algum motivo…

se você rodar um MySQL local será que dá a mesma coisa?

robertouba

Vou tentar isso hoje, mas primeiro vou instalar um server linux pra montar meu banco.

robertouba

Bom, tudo foi resolvido integrando com o c3p0.
Adicionando a biblioteca e configurando no hibernate, deu tudo certo, agora posso alterar diretamente no banco que não há problemas com cache.

Criado 27 de outubro de 2006
Ultima resposta 2 de jul. de 2011
Respostas 48
Participantes 7