2016-03-04 309 views
0

我知道要休眠。 我有一個SQL語句HQL查詢需要很長時間才能執行

SELECT VERSION_ID,D_BEGIN,D_END, 
(SELECT NAME FROM zvit where ZVIT_ID=version.ZVIT_ID) as name 
FROM version 
where VERSION_ID in 
(SELECT term.VERSION_ID FROM term 
where term.PERIOD_MONTH= :periodMonth and term.PERIOD_TYPE= :periodType and term.PERIOD_YEAR= :periodYear) 
order by 1 ; 

我試着用個createCriteria和HQL來實現它。

DetachedCriteria subQuery = DetachedCriteria.forClass(TermData.class) 
      .add(Restrictions.eq("periodmonth", periodMonth)) 
      .add(Restrictions.eq("periodtype", periodType)) 
      .add(Restrictions.eq("periodyear", periodYear)) 
      .setProjection(Projections.projectionList() 
        .add(Projections.property("versionId.versionId")) 
        );   
    Criteria versionCriteria = session.createCriteria(VersionData.class) 
      .addOrder(Order.asc("versionId")) 
      .add(Subqueries.propertyIn("versionId", subQuery)) 
      .createAlias("zvitId", "zvitId", org.hibernate.sql.JoinType.INNER_JOIN) 
      .setProjection(Projections.projectionList() 
        .add(Projections.property("versionId")) 
        .add(Projections.property("dbegin")) 
        .add(Projections.property("dend")) 
        .add(Projections.property("zvitId.name"), "name") 

        ); 

HQL:

  Query query = session.createQuery("" 
        + "from VersionData as version " 
//     + "inner join version.zvitId as zvit " 
        + "where version.versionId in " 
        + "(select term.versionId from TermData as term " 
        + "where term.periodmonth= :periodmonth and term.periodtype= :periodtype and term.periodyear= :periodyear)"); 

的問題是,這個HQL需要10倍更長的時間來執行。並做了很多不必要的查詢。我試圖與評論對象來做這件事,它改善了一點,但仍然工程5的時間比個createCriteria查詢時間更長,除了我得到VersionData和ZvitData對象我不能這樣做皈依

List<VersionData> queryResult = query.list(); 。這似乎不是一個問題,但我仍然不明白爲什麼我沒有收到只是VersionData對象。 但是還有一個更重要的問題是有沒有什麼辦法可以改善這個HQL語句,以便與mysql或createCriteria查詢同時執行。

VersionData defenition

@Entity 
@Table(name = "version") 
public class VersionData implements Serializable 
{ 

    /** 
    * 
    */ 
    private static final long serialVersionUID = 7355281418627668744L; 

    @Id 
    @Column(name="VERSION_ID") 
    private String versionId; 

    /** 
    * user dbegin 
    */ 
    @Column(name = "D_BEGIN") 
    @Type(type = "date") 
    private Date dbegin; 

    /** user dend */ 
    @Column(name = "D_END") 
    @Type(type = "date") 
    private Date dend; 


    /** 
    * user zvitId 
    */ 
    @ManyToOne 
    @JoinColumn(name="ZVIT_ID") 
    private ZvitData zvitId; 

    @OneToMany(targetEntity=TermData.class, mappedBy = "versionId", cascade=javax.persistence.CascadeType.ALL, fetch=FetchType.LAZY) 
    private List<TermData> terms; 
//getters, setters, hashcode, equals 
} 
+0

親愛的,發佈您的VersionData POJO定義。 –

+0

已添加版本數據 – Evgen

+0

對於每個VersionData,您都有一個TermData的列表,因此您必須在此添加TermData的定義。這是主要查詢深度的導入。 –

回答

1

好了,有了標準查詢你貼,你只取你需要的領域,同時又與你的HQL查詢您獲取整個Hibernate的管理實體(VersionData)。根據這個實體的配置方式,你可能會看到其他查詢被觸發來填充這個實體的字段。

您可能會對HQL做與標準相同的事情,在我看來,它比使用標準更容易理解,因此可以維護。僅僅定義你想取,用適當的構造領域的Java類MyClass的,並調用一個HQL查詢它看起來像:

"select new path.to.myclass.MyClass (" 
       + " alias1.field1, " 
       + " alias2.field2, " 
       + " ... " 

其中別名是你給的實體的名稱在您的HQL查詢(例如,version是您編寫的查詢中的VersionData的別名)。沒有預測,沒有額外的抽象,只是一個類似SQL的查詢。

而不是定義一個新的類來保存字段從HQL查詢返回的(我覺得這更方便),您可以直接獲取字段,然後處理結果返回,如下面的鏈接:

How to retrieve only certain fields of an entity in JPQL or HQL? What is the equivalent of ResultSet in JPQL or HQL?

+0

這是通常的做法,爲您想要獲取的字段創建一個新類。如果我有很多不同的查詢,我不需要獲取所有的VersionData模型,那麼與使用createCriteria或使用createQuery和長期選擇\t必需字段進行比較,製作大量類和HQL是非常有益的。我對維護HQL或createCriteria沒有任何經驗,所以我不知道什麼會更好。 – Evgen

+0

@Evgen您可以從'VersionData'擴展'MyClass'並使用結果轉換器填充它。對於嵌套投影,你可以添加一些setters。或者您可以直接將嵌套投影映射到'VersionData'。它需要一個特殊的定製變壓器。像[FluentHibernateResultTransformer](https:// github。COM/V-ladynev /流利-休眠/斑點/主/流利-休眠核/ SRC /主/ JAVA/COM/github上/流利/休眠/內部/變壓器/ FluentHibernateResultTransformer.java)。 –

+0

如果您不希望創建大量課程,請按照所示鏈接進行操作。另一方面,這些字段可以對應於,例如,列表中的行向最終用戶呈現,並且在這種情況下,我認爲將它們放在課堂中是有利的。至於通常的做法,我認爲Hibernate鼓勵開發人員使用他們的標準抽象而不是使用HQL查詢,因爲前者更「面向對象」。然而,根據我的個人經驗,使用標準的代碼難以維護,並且比HQL/JPQL查詢檢查正確性。 –

相關問題