基于EntityManager的分页查询解决方案

需求:分页查询学生信息

项目环境:Spring Boot 2.0.6.RELEASE

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.0.6.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>

Maven依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.38</version>
</dependency>

分页查询返回体类:

public class IPagination<T> {
    /** 当前页数 **/
    private int pager;
    /** 总页数 **/
    private int pages;
    /** 每页条数 **/
    private int size;
    /** 总条数 **/
    private long total;
    /** 忽略数据条数 **/
    private int offset;
    /** 列表数据 **/
    private List<T> list = new ArrayList<>();

    public IPagination() {
    }

    public IPagination(int pager, int size) {
        if (pager >= 1 && size >= 1) {
            this.pager = pager;
            this.size = size;
        } else {
            throw new RuntimeException("invalid pager: " + pager + " or size: " + size);
        }
    }

    public static IPagination create(int pager, int size) {
        return new IPagination(pager, size);
    }

    public void setTotal(long total) {
        this.total = total;
    }

    public void setList(List<T> list) {
        this.list = list;
    }

    public int getSize() {
        return size;
    }

    public int getPager() {
        return pager == 0 ? 1 : pager;
    }

    public int getOffset() {
        return size * (getPager() - 1);
    }

    public int getPages() {
        return Double.valueOf(Math.ceil((double) total / (double) size)).intValue();
    }

    public long getTotal() {
        return total;
    }

    public List<T> getList() {
        return list;
    }
}
View Code

Controller层:

@RestController
@RequestMapping("/api/student")
public class StudentApiController {

    @Autowired
    private StudentService studentService;

    @PostMapping("/search")
    public IPagination<StudentResponse> search(@RequestBody StudentSearchRequest request) {
        return studentService.search(request);
    }
}

就一个简单的POST请求,请求体有页数、每页条数、查询参数等属性。

Service层:

@Service
public class StudentService {

    @Autowired
    private PaginationMapper paginationMapper;

    /**
     * 分页查询学生信息
     * @param request
     * @return
     */
    public IPagination<StudentResponse> search(StudentSearchRequest request) {
        // 拼接SQL语句
        StringBuilder sql = new StringBuilder("SELECT id, name FROM t_galidun_student ");
        // 查询需要的参数,先存进Map
        Map<String, Object> maps = new HashMap<>();
        if (request.name != null) {
            sql.append("WHERE name LIKE :name");
            maps.put("name", "%" + request.name + "%");
        }
        // 调用通用方法返回查询结果
        return paginationMapper.nativeSearch(request.nowPage, request.pageSize, sql.toString(), maps, StudentResponse.class);
    }

}

在这一层主要是拼接sql,提供查询需要的参数,最后调用通用方法返回结果。

Mapper层:

@Component
public class PaginationMapper {

    @PersistenceContext
    private EntityManager entityManager;

    /**
     * 分页查询通用方法
     *
     * @param nowPage  当前页
     * @param pageSize 每页条数
     * @param sql      sql语句
     * @param maps     sql查询参数
     * @param clazz    返回类型
     * @param <T>
     * @return
     */
    public <T> IPagination<T> search(Integer nowPage, Integer pageSize, String sql, Map<String, Object> maps, Class<T> clazz) {
        // 初始化分页返回体
        IPagination pagination = IPagination.create(nowPage, pageSize);
        // 查询结果总条数
        int total = getQueryWithParameters(entityManager.createNativeQuery(sql), maps).getResultList().size();
        pagination.setTotal(total);
        if (total == 0) return pagination;
        Query query = getQueryWithParameters(entityManager.createNativeQuery(sql), maps);
        // 忽略指定条数据,返回一页数据
        query.setFirstResult(pagination.getOffset()).setMaxResults(pagination.getSize());
        // 指定返回对象类型
        query.unwrap(NativeQueryImpl.class).setResultTransformer(Transformers.aliasToBean(clazz));
        // 列表数据
        pagination.setList(query.getResultList());
        return pagination;
    }

    /**
     * 设置查询所需的参数
     *
     * @param query
     * @param maps
     * @return
     */
    private Query getQueryWithParameters(Query query, Map<String, Object> maps) {
        if (maps.size() > 0) {
            for (String key : maps.keySet()) {
                query.setParameter(key, maps.get(key));
            }
        }
        return query;
    }
}

 

这是个通用的方法,只需要传入查询的页数,每页数据条数,sql语句,查询参数,返回体类型即可。

每个Query只能调用一次getResultList方法,调用之后再次调用就会抛异常,所以方法中有两处entityManager.createNaticeQuery(sql),一次是为了查询总条数,另一次是查询当前页的数据。

查询总条数的时候可以改为使用COUNT(主键或者非NULL索引);读者有其他能提高查询性能的方法,方便的话,分享一下吧。

 

项目地址:https://github.com/Nguyen-Vm/entity-manager

 

转载于:https://www.cnblogs.com/NguyenVm/p/10033909.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
EntityManager提供了多种分页查询的方式,其中一种常用的方式是使用TypedQuery和CriteriaBuilder结合使用。 假设我们有一个实体类User,其中有三个属性:id、username和age。现在我们需要根据username和age进行分页查询,查询结果按照id升序排列。 以下是示例代码: ```java public List<User> findUsersByPage(String username, int age, int pageNum, int pageSize) { EntityManager entityManager = ...; // 获取EntityManager实例 CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder(); CriteriaQuery<User> criteriaQuery = criteriaBuilder.createQuery(User.class); Root<User> root = criteriaQuery.from(User.class); // 构建查询条件 List<Predicate> predicates = new ArrayList<>(); if (StringUtils.isNotBlank(username)) { predicates.add(criteriaBuilder.like(root.get("username"), "%" + username + "%")); } if (age > 0) { predicates.add(criteriaBuilder.equal(root.get("age"), age)); } criteriaQuery.where(predicates.toArray(new Predicate[0])); // 构建排序条件 criteriaQuery.orderBy(criteriaBuilder.asc(root.get("id"))); // 构建分页查询 TypedQuery<User> typedQuery = entityManager.createQuery(criteriaQuery); typedQuery.setFirstResult((pageNum - 1) * pageSize); typedQuery.setMaxResults(pageSize); // 执行查询并返回结果 return typedQuery.getResultList(); } ``` 在上述代码中,我们首先获取了EntityManager实例,并获取了CriteriaBuilder实例。然后,我们构建了一个CriteriaQuery<User>对象,并指定实体类为User。接着,通过调用criteriaQuery.from(User.class)方法获取了Root<User>对象,并开始构建查询条件和排序条件。 在构建查询条件时,我们先创建了一个Predicate列表,并根据传入的参数构建Predicate。如果username不为空,则添加一个模糊查询的Predicate;如果age大于0,则添加一个等于查询的Predicate。最后,将Predicate列表转换成数组,并设置为查询条件。 在构建排序条件时,我们调用了orderBy方法,并指定按照id升序排列。 最后,我们通过创建TypedQuery<User>对象,并设置分页参数,执行查询并返回结果。 需要注意的是,在调用getResultList方法之前,我们还可以调用其他方法设置查询缓存、锁定查询结果等。详细使用方法可以参考JPA的相关文档。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值