基於EntityManager的分頁查詢解決方案

需求:分頁查詢學生信息java

項目環境:Spring Boot 2.0.6.RELEASEmysql

<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依賴:git

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

分頁查詢返回體類:github

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層:spring

@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請求,請求體有頁數、每頁條數、查詢參數等屬性。sql

Service層:api

@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,提供查詢須要的參數,最後調用通用方法返回結果。app

Mapper層:ide

@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語句,查詢參數,返回體類型便可。spring-boot

每一個Query只能調用一次getResultList方法,調用以後再次調用就會拋異常,因此方法中有兩處entityManager.createNaticeQuery(sql),一次是爲了查詢總條數,另外一次是查詢當前頁的數據。

查詢總條數的時候能夠改成使用COUNT(主鍵或者非NULL索引);讀者有其餘能提升查詢性能的方法,方便的話,分享一下吧。

 

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

相關文章
相關標籤/搜索