jpa group by 统计总数错误

2021-04-02

一 先说问题

手写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)

不过还没找到它这加起来的目的是什么。。。淦 好像还是有点不放心

...