2017-01-18 2 views
0

Je suis confronté à un problème très étrange avec les critères d'hibernation dans mon application. Ci-dessous mentionné dans l'extrait de mon code source.hibernate critères requête créer plusieurs sql

Classe Entité

import java.io.Serializable; 

import javax.persistence.Column; 
import javax.persistence.Entity; 
import javax.persistence.GeneratedValue; 
import javax.persistence.GenerationType; 
import javax.persistence.Id; 
import javax.persistence.Table; 

import org.hibernate.annotations.Cache; 
import org.hibernate.annotations.CacheConcurrencyStrategy; 

@Entity 
@Table(name = "AIRPORT") 
@Cache(usage = CacheConcurrencyStrategy.READ_ONLY) 
public class Airport implements Serializable { 

    private static final long serialVersionUID = -7120581694566566178L; 
    private Long id; 
    private String countryCode; 
    private String countryName; 
    private String cityCode; 
    private String cityName; 
    private String airportCode; 
    private String airportName; 

    @Id 
    @GeneratedValue(strategy = GenerationType.IDENTITY) 
    @Column(name = "ID", unique = true) 
    public Long getId() { 
     return id; 
    } 

    public void setId(Long id) { 
     this.id = id; 
    } 

    @Column(name = "COUNTRY_NAME") 
    public String getCountryName() { 
     return countryName; 
    } 

    public void setCountryName(String countryName) { 
     this.countryName = countryName; 
    } 

    @Column(name = "COUNTRY_CODE", length = 10) 
    public String getCountryCode() { 
     return countryCode; 
    } 

    public void setCountryCode(String countryCode) { 
     this.countryCode = countryCode; 
    } 

    @Column(name = "CITY_CODE", length = 25) 
    public String getCityCode() { 
     return cityCode; 
    } 

    public void setCityCode(String cityCode) { 
     this.cityCode = cityCode; 
    } 

    @Column(name = "CITY_NAME") 
    public String getCityName() { 
     return cityName; 
    } 

    public void setCityName(String cityName) { 
     this.cityName = cityName; 
    } 

    @Column(name = "AIRPORT_CODE", unique = true, length = 10) 
    public String getAirportCode() { 
     return airportCode; 
    } 

    public void setAirportCode(String airportCode) { 
     this.airportCode = airportCode; 
    } 

    @Column(name = "AIRPORT_NAME") 
    public String getAirportName() { 
     return airportName; 
    } 

    public void setAirportName(String airportName) { 
     this.airportName = airportName; 
    } 
} 

Classe DAO

Criteria criteria = getSession().createCriteria(getTemplateClass()); 
    criteria.addOrder(Order.asc("countryCode")); 
    criteria.addOrder(Order.asc("cityCode")); 
    criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY); 
    criteria.setCacheable(true); 
    return (List<Airport>) criteria.list(); 

SQL généré lorsque l'application de démarrage et l'interrogation de résultat

Hibernate: select this_.ID as ID1_12_0_, this_.AIRPORT_CODE as AIRPORT_2_12_0_, this_.AIRPORT_NAME as AIRPORT_3_12_0_, this_.CITY_CODE as CITY_COD4_12_0_, this_.CITY_NAME as CITY_NAM5_12_0_, this_.COUNTRY_CODE as COUNTRY_6_12_0_, this_.COUNTRY_NAME as COUNTRY_7_12_0_ from AIRPORT this_ order by this_.COUNTRY_CODE asc, this_.CITY_CODE asc 

Si j'appelle encore le même code et supposons que j'ai la liste 1000 aéroports alors il exécute la requête ci-dessous 1000 fois. Ce comportement est assez étrange.

Hibernate: select airport0_.ID as ID1_12_0_, airport0_.AIRPORT_CODE as AIRPORT_2_12_0_, airport0_.AIRPORT_NAME as AIRPORT_3_12_0_, airport0_.CITY_CODE as CITY_COD4_12_0_, airport0_.CITY_NAME as CITY_NAM5_12_0_, airport0_.COUNTRY_CODE as COUNTRY_6_12_0_, airport0_.COUNTRY_NAME as COUNTRY_7_12_0_ from AIRPORT airport0_ where airport0_.ID=? 
Hibernate: select airport0_.ID as ID1_12_0_, airport0_.AIRPORT_CODE as AIRPORT_2_12_0_, airport0_.AIRPORT_NAME as AIRPORT_3_12_0_, airport0_.CITY_CODE as CITY_COD4_12_0_, airport0_.CITY_NAME as CITY_NAM5_12_0_, airport0_.COUNTRY_CODE as COUNTRY_6_12_0_, airport0_.COUNTRY_NAME as COUNTRY_7_12_0_ from AIRPORT airport0_ where airport0_.ID=? 
Hibernate: select airport0_.ID as ID1_12_0_, airport0_.AIRPORT_CODE as AIRPORT_2_12_0_, airport0_.AIRPORT_NAME as AIRPORT_3_12_0_, airport0_.CITY_CODE as CITY_COD4_12_0_, airport0_.CITY_NAME as CITY_NAM5_12_0_, airport0_.COUNTRY_CODE as COUNTRY_6_12_0_, airport0_.COUNTRY_NAME as COUNTRY_7_12_0_ from AIRPORT airport0_ where airport0_.ID=? 
........ 
........ 

Même moi, je me sers ehcache et même la ligne ci-dessous dans mes critères.

criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY); 

Toute aide serait grandement appréciée.

+1

Essayez de supprimer 'setCacheable (true)' –

+0

@JimmyT. Cette solution a fonctionné, mais je ne comprends pas pourquoi le cache crée autant de SQL si le résultat est mis en cache. –

+1

L'entrée de cache pour une requête contient uniquement les ID des objets. Si la requête est trouvée dans le cache, Hibernate recherchera ensuite les objets dans le cache. Si le résultat de la requête est dans le cache mais que les objets ne le sont pas, Hibernate chargera les objets de la base de données via leur ID. –

Répondre

0

Je peux penser à quelques raisons pour lesquelles cela pourrait être survenant:

  1. Votre entité a une association définie dans ce qui est configuré pour désireux joindre par défaut et vous avez également indiqué que l'utilisation de l'association FetchMode.SELECT. (Ceci est connu comme le problème N + 1)

  2. Alors que la transaction est toujours ouverte, vous interagissez avec une association de chaque objet Airport qui est défini sur chargement paresseux. En interagissant, je veux dire, vous utilisez un getter pour accéder à la relation, forçant Hibernate à déproxy l'entité associée. Comme la déproxication est en cours avec la transaction encore ouverte et que l'entité associée n'a pas encore été chargée, Hibernate récupère automatiquement l'association pour vous. Vous avez écrit le hashcode ou les méthodes égales de votre entité Airport pour utiliser une propriété d'une association qui n'est pas jointe avec impatience et force hibernate à déproxy, et ainsi récupérer l'entité déchargée, pendant la transaction.

+0

Devinettes rationnelles. Ce qui me rend confus, c'est que, d'après la question elle-même, il semble que: 1) Le fetch N + 1 va aussi chercher «l'aéroport», ce qui implique que l'association est entre «aéroport» et «aéroport». 2) A partir des requêtes générées, il n'y a pas d'indication d'une telle association: ce n'est pas une relation ~ ToOne car la première requête n'a pas de champs pour un autre aéroport. Cela ne semble pas une relation ~ ToMany parce que les requêtes supplémentaires demandent simplement l'aéroport par ID. Je soupçonne qu'il est causé par quelque chose d'autre (votre 2 ou 3 peut-être), ou OP ne cite pas le SQL complet –

+0

@Peter Il n'y a pas de relation avec une autre entité. J'ai ajouté par classe d'entité pour votre référence. –