在我的JSF数据表中,我实现了延迟加载,当我对记录进行分页时,执行下一组记录大约需要4到5秒的时间,实际上执行结果应该少于一秒钟。
这是我实现它的方式所发生的,不确定我该如何解决。
扩展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; }
和道课
@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,这是我每页的默认记录数。
this.setRowCount(requestList.size());
更新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个查询 ,一个用于计数过滤后的resultSet(我让db进行计数),另一个用于检索分页的resultSet(我让db提取子列表)。即使对于包含数百万行的表,我也从未经历过明显的延迟。
遵循有关排序和过滤的具体示例。所有代码都使用JPA标准(没有Hibernate或Spring自定义功能)。CriteriaQuery在这种情况下,特别指出了这种方法。
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(); } }