一 先说问题
手写specification时,如果group by且分页,那么获得的总数总是大于实际(group by后的)总数。
二 原因
//源码在这个类里
package org.springframework.data.jpa.repository.support;
public class SimpleJpaRepository<T, ID> implements JpaRepositoryImplementation<T, ID> {
@Override
public Page<T> findAll(@Nullable Specification<T> spec, Pageable pageable) {
TypedQuery<T> query = getQuery(spec, pageable);
return isUnpaged(pageable) ? new PageImpl<T>(query.getResultList())
: readPage(query, getDomainClass(), pageable, spec);
}
protected <S extends T> Page<S> readPage(TypedQuery<S> query, final Class<S> domainClass, Pageable pageable,
@Nullable Specification<S> spec) {
if (pageable.isPaged()) {
query.setFirstResult((int) pageable.getOffset());
query.setMaxResults(pageable.getPageSize());
}
return PageableExecutionUtils.getPage(query.getResultList(), pageable,
() -> executeCountQuery(getCountQuery(spec, domainClass)));
}
private static long executeCountQuery(TypedQuery<Long> query) {
Assert.notNull(query, "TypedQuery must not be null!");
List<Long> totals = query.getResultList();
long total = 0L;
//group 后每条记录的重复次数 它给加起来了,所以我们获得的统计数总是大于实际
for (Long element : totals) {
total += element == null ? 0 : element;
}
return total;
}
}
三 解决办法--继承SimpleJpaRepository类重写findAll方法:
public class MySimpleJparepository<T,ID extends Serializable> extends SimpleJpaRepository <T,Serializable>{
public MySimpleJparepository(JpaEntityInformation<T, ?> entityInformation, EntityManager entityManager) {
super(entityInformation, entityManager);
}
public MySimpleJparepository(Class<T> domainClass, EntityManager em) {
super(domainClass, em);
}
@Override
public Page<T> findAll(Specification<T> spec, Pageable pageable) {
TypedQuery<T> query = getQuery(spec, pageable);
return isUnpaged(pageable) ? new PageImpl<T>(query.getResultList())
: readPage(query, getDomainClass(), pageable, spec);
}
private static boolean isUnpaged(Pageable pageable) {
return pageable.isUnpaged();
}
protected <S extends T> Page<S> readPage(TypedQuery<S> query, final Class<S> domainClass, Pageable pageable,
@Nullable Specification<S> spec) {
if (pageable.isPaged()) {
query.setFirstResult((int) pageable.getOffset());
query.setMaxResults(pageable.getPageSize());
}
return PageableExecutionUtils.getPage(query.getResultList(), pageable,
() -> executeCountQuery(getCountQuery(spec, domainClass)));
}
private static long executeCountQuery(TypedQuery<Long> query) {
Assert.notNull(query, "TypedQuery must not be null!");
List<Long> totals = query.getResultList();
//把加起来的逻辑给去掉
return totals.size();
}
}
四 启动类加注解注入我们新的实现类
@EnableJpaRepositories(repositoryBaseClass = MySimpleJparepository.class)
不过还没找到它这加起来的目的是什么。。。淦 好像还是有点不放心
...