2015-10-14 67 views
0

我使用Spring Data JPA + Hibernate作爲webapp。對於特定的域模型A,我們在另一個域B中有一對多關聯。這樣A將有一個Set getB(),B將有一個getA()。JPA雙向1..N關聯,避免在子查詢中設置父項

查詢A圖時,我看到hibernate使用1 + n查詢。用於獲取A圖的單個外連接查詢,然後在每個B中設置A的'n'查詢。

我在這裏是否缺少任何模式?既然所有的孩子都有同一個父母,是不是可以避免這些'n'查詢呢?





    @MappedSuperclass 
    @Data 
    public abstract class Batch implements Serializable { 

     private static final long serialVersionUID = 1L; 

     @OneToOne(fetch = FetchType.EAGER) 
     @JoinColumn(name = "batch_id", referencedColumnName = "batch_id") 
     protected BatchID batchId; 

    } 


    /* 
    //The parent class in a simplified form 
    */ 
    @Entity 
    @Table(name = "DRYRUN") 
    @Inheritance(strategy=InheritanceType.TABLE_PER_CLASS) 
    public class DryrunBatch extends Batch { 

     /** 
     * 
     */ 
     private static final long serialVersionUID = -1596595930859735318L; 
     @Id 
     @GeneratedValue(strategy = GenerationType.AUTO) 
     @[email protected] 
     protected Long id; 

     public DryrunTNStatus newTNStatus() 
     { 
     final DryrunTNStatus tn = new DryrunTNStatus(); 
     tn.setBatch(this); 
     getTnStatus().add(tn); 
     return tn; 
     } 

     @OneToMany(fetch = FetchType.LAZY, mappedBy = "batch") 
     @[email protected] 
     private Set tnStatus = new HashSet(); 
    } 


    //The child class in a simplified form 

    @Entity 
    @Table(name = "DRYRUN_TN_STATUS") 
    @Data 
    public class DryrunTNStatus implements Serializable{ 

     /** 
     * 
     */ 
     private static final long serialVersionUID = -4388406636444350023L; 

     public DryrunTNStatus(String accountNo, String telNo) { 
     super(); 

     this.accountNo = accountNo; 
     this.telNo = telNo; 
     } 

     @ManyToOne(fetch = FetchType.LAZY) 
     @JoinColumn(name = "BATCH_ID", referencedColumnName = "BATCH_ID") 
     private DryrunBatch batch; 

     public DryrunTNStatus() 
     { 

     } 
     @Id 
     @GeneratedValue(strategy = GenerationType.AUTO) 
     protected Long id; 

    } 

使用JpaRepository獲取對象圖的代碼。使用Spring JPA支持來執行外部聯接。我更喜歡Hibernate的@Fetch註釋。



    DryrunBatch drBatch = drBatchRepo.findOne(new Specification() { 

      @Override 
      public Predicate toPredicate(Root root, CriteriaQuery query, 
       CriteriaBuilder cb) { 
      query.distinct(true); 
      root.fetch("tnStatus", JoinType.LEFT); 
      return cb.equal(root.get("batchId").get("id"), 
       batch.getId()); 

      } 
     }); 

最後從日誌中查詢hibernate。我運行一個junit,從DB獲取10個孩子的父母。



    //this query can fetch data for the complete graph?? 
    Hibernate: select distinct dryrunbatc0_.id as id1_6_0_, tnstatus1_.id as id1_9_1_[etc..] from dryrun dryrunbatc0_ left outer join dryrun_tn_status tnstatus1_ on dryrunbatc0_.batch_id=tnstatus1_.batch_id where dryrunbatc0_.batch_id=15 

    //and then 10 queries like 
    Hibernate: select dryrunbatc0_.id as id1_6_3_, [etc..] from dryrun dryrunbatc0_ left outer join batch_id batchid1_ on dryrunbatc0_.batch_id=batchid1_.batch_id inner join users user2_ on dryrunbatc0_.created_by=user2_.login_id left outer join dryrun_tn_status tnstatus3_ on dryrunbatc0_.batch_id=tnstatus3_.batch_id where dryrunbatc0_.batch_id=? 

+0

您是否嘗試過FetchMode https://www.google.de/search?q=hibernate+%40Fetch%28FetchMode.SELECT%29&ie=utf-8&oe=utf-8&gws_rd=cr&ei=iyseVtKDGIX4ULi5vagD – HRgiger

+0

@HRgiger是的,我試過JOIN ,SUBSELECT也是如此。沒有任何區別。 –

回答

0

您遇到了着名的N + 1延遲加載問題。沒有JPA標準的方法來解決這個問題,但是,每個JPA提供者都提供了打開「批量提取」的方法,它將一次加載所有惰性引用,而不是每個都加載到一個SQL查詢中。

以下是關於如何在hibernate中打開它的信息。

這是一個article,它解釋了批量抓取的工作原理和使用eclipselink的示例。