如何使用延迟加载和分页查询Primefaces dataTable的数据 [英] How to query data for Primefaces dataTable using lazy loading and pagination
问题描述
在我的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屋!