2012-12-20 52 views
20

在我的JSF的數據表中,我已經實現了延遲加載,當通過記錄進行分頁時,需要花費大約4或5秒的時間來執行下一組記錄,實際上它應該是採取不到一秒的時間來執行結果。如何使用延遲加載和分頁查詢Primefaces數據表的數據

這發生在我已經實現它的方式,不知道我怎麼能解決這個問題。

延伸LazyDataModel

@Override 
public List<Request> load(int startingAt, int maxPerPage, String sortField, 
          SortOrder sortOrder, Map<String, String> filters) 
{ 
    requestList = requestService.getRequest(startingAt, maxPerPage, 
              sortField, sortOrder, filters); 
    this.setRowCount(requestList.size()); 
    if (requestList.size() > maxPerPage) 
    { 
     System.out.println("executing"); 
     return requestList.subList(startingAt, startingAt + maxPerPage); 
    } 
    else 
    { 
     System.out.println("executing else "); 
     return requestList; 
    } 

    return requestList; 
} 

和DAO類的DataModel類

@Override 
public List<Request> getRequest(int startingAt, int maxPerPage, 
           String sortField, SortOrder sortOrder, Map<String, String> filters) 
{ 
    Criteria criteria = sessionFactory.getCurrentSession().createCriteria(
          Request.class); 
    criteria.addOrder(Order.desc("requestNo")); 
    for (Map.Entry<String, String> entry : filters.entrySet()) 
    { 
     if (entry.getValue() != null) 
     { 
      criteria.add(Restrictions.ilike("requestNo", 
              "%" + entry.getValue() + "%")); 
     } 
    } 
    //criteria.setMaxResults(maxPerPage); 
    //criteria.setFirstResult(startingAt); 
    return criteria.list(); 
} 

有人能解釋一下是什麼原因導致在通過記錄分頁這種延遲?

如果我刪除以下

if (requestList.size() > maxPerPage) 
{ 
    System.out.println("executing"); 
    return requestList.subList(startingAt, startingAt + maxPerPage); 
} 
else 
{ 
    System.out.println("executing else "); 
    return requestList; 
} 

和執行,那麼它是完全執行無延遲,但問題是this.setRowCount(requestList.size());總是5這是我的每頁記錄的默認號碼。

更新2

@Override 
    public List<Request> load(int startingAt, int maxPerPage, String sortField, 
      SortOrder sortOrder, Map<String, String> filters) { 
     requestList = requestService.getRequest(startingAt, maxPerPage, 
       sortField, sortOrder, filters); 
     this.setRowCount(requestService.getRequestCount()); 
     if (requestService.getRequestCount() > maxPerPage) { 
      try { 

       return requestList.subList(startingAt, startingAt + maxPerPage); 
      } catch (IndexOutOfBoundsException e) { 
       //e.printStackTrace(); 
       return requestList.subList(startingAt, startingAt 
         + (requestService.getRequestCount() % maxPerPage)); 
      } 
     } else { 
      return requestList; 
     }  
    } 

用於使用得到的結果集的數量不同的查詢以下

@Override 
    public int count() { 
     int count = ((Long) sessionFactory.getCurrentSession() 
       .createQuery("select count(*) from Request").uniqueResult()) 
       .intValue(); 
     System.out.println(" count size " + count); 
     return count; 
    } 

和吾道

@Override 
     public List<Request> getRequest(int startingAt, int maxPerPage, 
       String sortField, SortOrder sortOrder, Map<String, String> filters) { 
      Criteria criteria = sessionFactory.getCurrentSession().createCriteria(
        Request.class); 
      criteria.addOrder(Order.desc("requestNo")); 
      for (Map.Entry<String, String> entry : filters.entrySet()) { 
       if (entry.getValue() != null) { 
        criteria.add(Restrictions.ilike("requestNo", 
          "%" + entry.getValue() + "%"));   } 
      } 
      criteria.setMaxResults(maxPerPage); 
      criteria.setFirstResult(startingAt);  
       return criteria.list(); 

     } 

回答

26

在非常大導致列表的情況下, Java端計數子目錄操作可能會對內存使用造成危險,因此也會影響性能。

相反,我通常有下面幾種方法去:使用2查詢,一個用於計算過濾的ResultSet(而我讓DB做計數),另一個用於檢索分頁的ResultSet(而我讓DB提取物子列表)。 即使在包含數百萬行的表格中,我從來沒有經歷過嚴重的延遲。

遵循一個具體的例子排序和過濾。所有代碼都使用JPA標準(沒有Hibernate或Spring自定義功能)CriteriaQuery方法在這種情況下特別指出。

爲myBean類

@ManagedBean 
@ViewScoped 
public class MyBean { 
    @EJB 
    private MyObjFacade myObjFacade; 
    private LazyDataModel<MyObjType> model;  // getter and setter 

    @PostConstruct 
    public void init() { 
     model = new LazyDataModel<MyObjType>() { 

      @Override 
      public List<MyObjType> load(int first, int pageSize, String sortField, SortOrder sortOrder, Map<String, String> filters) { 
       model.setRowCount(myObjFacade.count(filters)); 
       return myObjFacade.getResultList(first, pageSize, sortField, sortOrder, filters); 
      } 
     }; 
     model.setRowCount(myObjFacade.count(new HashMap<String, String>())); 
    } 
} 

MyObjFacade類

@Stateless 
public class MyObjFacade { 
    @PersistenceContext 
    private EntityManager em; 
    @EJB 
    private MyObjFacade myObjFacade; 

    private Predicate getFilterCondition(CriteriaBuilder cb, Root<MyObjType> myObj, Map<String, String> filters) { 
     Predicate filterCondition = cb.conjunction(); 
     String wildCard = "%"; 
     for (Map.Entry<String, String> filter : filters.entrySet()) { 
      String value = wildCard + filter.getValue() + wildCard; 
      if (!filter.getValue().equals("")) { 
       javax.persistence.criteria.Path<String> path = myObj.get(filter.getKey()); 
       filterCondition = cb.and(filterCondition, cb.like(path, value)); 
      } 
     } 
     return filterCondition; 
    } 

    public int count(Map<String, String> filters) { 
     CriteriaBuilder cb = getEntityManager().getCriteriaBuilder(); 
     CriteriaQuery<Long> cq = cb.createQuery(Long.class); 
     Root<MyObjType> myObj = cq.from(MyObjType.class); 
     cq.where(myObjFacade.getFilterCondition(cb, myObj, filters)); 
     cq.select(cb.count(myObj)); 
     return em.createQuery(cq).getSingleResult().intValue(); 
    } 

    public List<MyObjType> getResultList(int first, int pageSize, String sortField, SortOrder sortOrder, Map<String, String> filters) { 
     CriteriaBuilder cb = getEntityManager().getCriteriaBuilder(); 
     CriteriaQuery<MyObjType> cq = cb.createQuery(MyObjType.class); 
     Root<MyObjType> myObj = cq.from(MyObjType.class); 
     cq.where(myObjFacade.getFilterCondition(cb, myObj, filters)); 
     if (sortField != null) { 
      if (sortOrder == SortOrder.ASCENDING) { 
       cq.orderBy(cb.asc(myObj.get(sortField))); 
      } else if (sortOrder == SortOrder.DESCENDING) { 
       cq.orderBy(cb.desc(myObj.get(sortField))); 
      } 
     } 
     return em.createQuery(cq).setFirstResult(first).setMaxResults(pageSize).getResultList(); 
    } 
} 
+0

我嘗試了2個不同的查詢,我通過編輯我的問題將我的代碼添加爲Update 2。這裏的問題是,當我分頁到第二頁時,我得到了'java.lang.IndexOutOfBoundsException',即使我正在捕獲該異常,請參閱我的代碼。這可能是什麼原因? – user75ponic

+0

您還需要在計數查詢中使用過濾器。 – perissf

+0

你可以提供一個例子,如何獲得1)一個用於計數過濾的結果集(我讓數據庫做的)2)用於檢索分頁結果集(我讓數據庫提取子列表)。謝謝 – user75ponic

2

我不知道這是否是在這種情況下有關,但增加了@ perissf的意見,我會關注關於以下內容:

if (entry.getValue() != null) 
{ 
    criteria.add(Restrictions.ilike("requestNo", 
            "%" + entry.getValue() + "%")); 
} 

對於這樣就解決了進入到

WHERE UPPER(request_no) LIKE '%VALUE%' 

類似於查詢這將全表掃描,作爲request_no指數不能在這種情況下使用,這將是有大量行的表很慢原因有兩個:

  • UPPER(request_no)需要一個功能索引。
  • like '%anything'無論功能指標是否存在,都必須查看每個值request_no
+0

感謝您指出這一點。那麼避免全表掃描的最佳方法是什麼? – user75ponic

+1

取決於你想要做什麼。在請求編號內查找子字符串是否有意義?你能忍受'喜歡'價值%''嗎? 'requestNo'是一個數字還是一個字符串? – beny23

+0

對於這些問題,可能值得提出另一個問題。 – beny23

相關問題