如何使用延迟加载和分页查询Primefaces dataTable的数据 [英] How to query data for Primefaces dataTable using lazy loading and pagination

查看:93
本文介绍了如何使用延迟加载和分页查询Primefaces dataTable的数据的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



这种情况发生在我已经实现的方式上,不确定如何解决这个问题。



DataModel扩展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,过滤器);
this.setRowCount(requestList.size());
if(requestList.size()> maxPerPage)
{
System.out.println(execution);
返回requestList.subList(startingAt,startingAt + maxPerPage);
}
else
{
System.out.println(executed else);
返回requestList;
}

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

有人可以解释是什么原因导致了记录分页的延迟?



如果我删除以下内容:

  if(requestList.size()> maxPerPage)
{
System.out.println(执行);
返回requestList.subList(startingAt,startingAt + maxPerPage);
}
else
{
System.out.println(executed else);
返回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();
返回requestList.subList(startingAt,startingAt
+(requestService.getRequestCount()%maxPerPage));
}
} else {
return requestList;




$ b $ p
$ b

使用不同的查询来获得使用以下

  @Override 
public int count(){
int count =((Long)sessionFactory。 getCurrentSession()
.createQuery(从请求中选择count(*))uniqueResult())
.intValue();
System.out.println(count size+ 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)); (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执行计数),另一个用于检索分页结果集(我让数据库提取子列表)。
我从来没有经历过显着的延迟,即使在包含数百万行的表中也是如此。



遵循一个具体排序和过滤的例子。所有代码都使用JPA标准(没有Hibernate或Spring自定义功能)。
MyBean class

  @ManagedBean 
@ViewScoped
public class MyBean {
@EJB
MyObjFacade myObjFacade;
private LazyDataModel< MyObjType>模型; // getter和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));
返回myObjFacade.getResultList(首先,pageSize,sortField,sortOrder,filters);
}
};
model.setRowCount(myObjFacade.count(new HashMap< String,String>()));


MyObjFacade类 p>

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

私有谓词getFilterCondition(CriteriaBuilder cb,Root< MyObjType> myObj,Map< String,String> filters){
Predicate filterCondition = cb.conjunction();
String wildCard =%; (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;

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

公共列表< 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();
}
}


In my JSF's datatable I have implemented lazy loading and when I paginate through records it is taking time about 4 or 5 seconds to execute next set of records, actually it should be take less than a second to execute the results.

This has happened to the way I have implemented it, not sure how could I resolve this.

DataModel class which extends 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;
}

and in dao class

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

Could someone explain what caused this delay in paginating through the records?

If I remove the following

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

and execute, then it is executes perfectly without delay, however the problem is this.setRowCount(requestList.size()); always 5 which is my default number of records per page.

Update 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;
        }       
    }

Used a different query for getting count of resultset using the following

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

and my 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(); 

        }

解决方案

In case of very large resulting lists, the Java-side counting and the sublisting operations can be dangerous for the memory usage and consequently also on the performance side.

Instead, I usually go with the following approach: use 2 queries, one for counting the filtered resultSet (I let the db do the count), and another one for retrieving the paginated resultSet (I let the db extract the sublist). I have never experienced significant delays, even with tables containing millions of rows.

Follows a concrete example with sorting and filtering. All the code uses JPA standard (no Hibernate or Spring custom features) The CriteriaQuery approach is particularly indicated in such situations.

MyBean class

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

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

这篇关于如何使用延迟加载和分页查询Primefaces dataTable的数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆