如何使用延迟加载和分页查询Primefaces dataTable的数据

在我的JSF的数据表中,我实现了延迟加载,当我通过logging进行分页时,需要花费大约4或5秒的时间来执行下一组logging,实际上,执行结果应该花费不到一秒的时间。

这发生在我已经实施的方式,不知道我怎么能解决这个问题。

扩展了LazyDataModel的DataModel类

@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课

 @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(); } 

有人可以解释是什么原因造成这种延迟通过logging分页?

如果我删除以下

 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,这是我每页默认的logging数。

更新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(); } 

如果结果列表非常大,则Java端计数和子列表操作对于内存使用以及性能方面都可能是危险的。

相反,我通常采用以下方法: 使用2个查询 ,一个用于计算过滤的结果集(我让db执行计数),另一个用于检索分页结果集(我让db提取子列表)。 即使在包含数百万行的表格中,我也从来没有经历过严重的延迟。

遵循一个具体的例子sorting和过滤。 所有代码都使用JPA标准(没有Hibernate或Spring自定义function) 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(); } } 

我不确定这是否与此相关,但join@ perissf的观察,我会关注以下内容:

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

为此将parsing成类似的查询

 WHERE UPPER(request_no) LIKE '%VALUE%' 

这将是全表扫描,因为request_no上的索引不能在这个实例中使用,这对于具有大量行的表是非常慢的,原因有两个:

  • UPPER(request_no)将需要一个function索引。
  • like '%anything' ,不pipe函数索引是否存在,都必须查看request_no每个值。