2017-01-18 73 views
0

我在我的應用程序中遇到了一個非常奇怪的問題與休眠條件。下面在我的源代碼片段中提到。休眠條件查詢創建多個sql

實體類

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; 
    } 
} 

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啓動應用程序和查詢結果時

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 

如果我再次調用相同的代碼並假設我有1000個機場列表,那麼它執行1000次以下的查詢。這種行爲很奇怪。

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=? 
........ 
........ 

即使我使用的Ehcache甚至低於線在我的標準。

criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY); 

任何幫助將不勝感激。

+1

嘗試刪除'setCacheable(true)' –

+0

@JimmyT。此解決方案工作,但我不明白爲什麼緩存創建如此多的SQL如果結果被緩存。 –

+1

查詢的緩存條目僅包含對象的ID。如果在緩存中找到查詢,Hibernate會在下一步查找緩存中的對象。如果查詢結果在緩存中但對象不是,那麼Hibernate會通過它的ID從數據庫加載對象。 –

回答

0

我能想到的幾個不同的原因,這可能會發生的歷史:

  1. 你的實體有被配置爲渴望在它定義的關聯默認加入,你也規定,該協會利用FetchMode.SELECT。 (這被稱爲N + 1問題)

  2. 雖然交易仍處於開放狀態,但您正在與每個設置爲延遲加載的Airport對象的關聯進行交互。通過交互,我的意思是,你使用getter來訪問關係,迫使Hibernate去除關聯的實體。由於事務處於打開狀態,並且關聯的實體尚未加載,因此Hibernate會自動爲您提取關聯。

  3. 你已經寫好機場實體的hashcode或者equals方法來使用一個未被熱切加入的關聯屬性,並迫使hibernate去掉deproxy,從而在事務中取出卸載的實體。

+0

合理的猜測。令我困惑的是,從問題本身來看,似乎是這樣的:1)N + 1取指也取得了「機場」,這意味着該關聯在「機場」和「機場」之間。 2)從生成的查詢中,沒有提示這種關聯:它不是ToOne關係,因爲第一個查詢沒有另一個機場的字段。這似乎不是ToMany關係,因爲額外的查詢只是通過ID來查詢機場。我懷疑它是由其他東西(你的2或3)引起的,或者OP沒有引用完整的SQL –

+0

@Peter與其他實體沒有任何關係。我已經添加了實體類供您參考。 –