2009-12-28 1 views
6

Je l'expérience de ce qui suit d'émission apparemment sans papier, et je veux comprendre siHibernate Objets de cache de second niveau qui sont paresseux = faux, aboutissent à une fetch par défaut = join, est-il documenté n'importe où?

  1. Je l'ai fait quelque chose de mal
  2. Est-ce que quelqu'un rencontre le même problème?
  3. Est-il vraiment documenté nulle part? ou ai-je oublié quelque chose?

Le comportement est ce Assumer le mapping suivant

<class name="org.sample.Foo" table="foo"> 
    ... 
    <many-to-one name="bar" class="org.sample.Bar"/> 
</class> 


<class name="org.sample.Bar" table="bar" lazy="false"> 
    ... 
</class> 

Tout d'abord, en arrière-plan, Hibernate valeur par défaut pour la d'extraction attribut sur un grand nombre à une relation doit être "sélectionner ", c'est au moins ce qui est documenté (j'ajouterai le lien ici quand je le trouverai)

Cependant, ceci n'est apparemment vrai que si la classe référencée est lazy =" true "!

donc apparemment la correspondance ci-dessus se traduit dans ce (parce que Bar est paresseux = « false »):

<class name="org.sample.Foo" table="foo"> 
    ... 
    <many-to-one name="bar" class="org.sample.Bar" *fetch="join" /> 
</class> 


<class name="org.sample.Bar" table="bar" lazy="false"> 
    ... 
</class> 

Maintenant, pourquoi serait-ce un problème? au lieu de 2 sélectionne, Hibernate chargera la référence non paresseux dans un seul sélectionner avec son « parent » (charge Foo avec Bar dans un Unique.Sélectionnez)

cela fait réellement sens, puisque l'objet est pas paresseux, pourquoi ne pas charger il?

La réponse est la suivante: que se passe-t-il si Bar est dans le cache de 2ème niveau?

<class name="org.sample.Foo" table="foo"> 
    ... 
    <many-to-one name="bar" class="org.sample.Bar" *fetch="join" /> 
</class> 


<class name="org.sample.Bar" table="bar" lazy="false"> 
    <cache usage="transactional" /> 
    ... 
</class> 

Et la réponse à cela est - rien ne change!

Apparemment, on pourrait supposer que Hibernate est assez intelligent pour comprendre que les objets de ce type ne doivent pas être chargés, mais puisque le chargement par défaut est passé de select à rejoindre, Hibernate n'a pas le choix (vous ne pouvez pas joindre un vraie table avec le 2ème cache de niveau, encore)

ainsi Hibernate fait ce qu'il est dit, et utilise une jointure pour aller chercher un objet à partir de la base de données où il est déjà dans le 2ème niveau cache

la solution que je trouve est de modifier littéralement le mappage à fetch = "select"

Maintenant, lorsque la seconde sélection pour Bar est Sur le point de partir, Hibernate comprend qu'il ne devrait pas aller à la base de données et l'extrait du cache. et une seule requête s'exécutera (après le préchauffage)

+0

Le comportement d'extraction dépend de l'API que vous utilisez pour interroger les objets. Utilisez-vous l'API HQL ou Criteria? – skaffman

+0

Ni l'un ni l'autre, un simple session.load (Foo.class, id) –

Répondre

4

J'ai rencontré le même problème et je me suis retrouvé à marquer toutes les relations plusieurs-à-un qui seront mises en cache comme fetch="select". Au moment où la requête est construite, Hibernate ne peut pas savoir si l'instance demandée de Bar est dans le cache de second niveau ou non (en supposant que Foo n'est pas en cache).

+0

Mais n'est-ce pas bizarre qu'il ne soit pas documenté, pas même dans les livres commerciaux officiels?Même dans les forums ou ici dans SO, je n'ai trouvé aucune mention de ce problème ... –

+0

Je suis d'accord. Mais pour comprendre ce que fait exactement Hibernate, je dois souvent mettre en session SQL et regarder ce qui se passe réellement. – bertolami

Questions connexes