jpa使用@Query自定義分頁查詢報錯You have an error in your SQL syntax; check the manual that corresponds t...

因為業(yè)務(wù)需要一個分頁查詢的列表,但是對數(shù)據(jù)內(nèi)容有去重的需求,簡單了解了JPA的@Query注解使用方式后就直接用了自定義sql來做,測試通過后上線測了兩筆也沒問題就沒太在意。但是隔了一天運營就反應(yīng)說功能報錯了,而且我去看日志發(fā)現(xiàn)報錯很奇怪,是sql語法錯誤,如果是sql語法錯誤那么是怎么測試通過的呢?報錯如下:

Error Code: 1064. You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '*) from test a where a.id in (select max(b.id) from test' at line 1

但是我寫的sql在結(jié)果集那里是沒有括號的

select a.* from test a where a.id in (select max(b.id) from test b group by name) order by a.id desc;

這個括號是如何生成的呢,經(jīng)過反復(fù)的測試樣本測試之后發(fā)現(xiàn),這個是jpa在做分頁需要查詢總數(shù)量的時候自動加了一個sql

select count(a.*) from test a where a.id in (select max(b.id) from test b group by name) order by a.id desc;

這個語法在高版本的mysql中是不支持的,只能寫成

select count(*) from test a where a.id in (select max(b.id) from test b group by name) order by a.id desc;

那么一開始又是怎么測試通過的呢,為什么有的查詢(pageSize>count)jpa不會加上count(pageSize<count)而有的又會自動count?
debug到j(luò)pa源碼之后,才知道jpa在執(zhí)行分頁查詢的時候有對記錄總數(shù)的獲取方式做優(yōu)化,具體實現(xiàn)在org.springframework.data.repository.support.PageableExecutionUtils的getPage方法,jpa就是通過這個方法將結(jié)果集封裝成page,而其中在計算total的時候會判斷當(dāng)前頁偏移量,當(dāng)前pageSize是否大于查詢條件的pageSize,如果能直接計算出來total就不會調(diào)用count去數(shù)據(jù)庫查詢記錄總數(shù)

/**
     * Constructs a {@link Page} based on the given {@code content}, {@link Pageable} and {@link Supplier} applying
     * optimizations. The construction of {@link Page} omits a count query if the total can be determined based on the
     * result size and {@link Pageable}.
     *
     * @param content must not be {@literal null}.
     * @param pageable must not be {@literal null}.
     * @param totalSupplier must not be {@literal null}.
     * @return the {@link Page}.
     */
    public static <T> Page<T> getPage(List<T> content, Pageable pageable, LongSupplier totalSupplier) {

        Assert.notNull(content, "Content must not be null!");
        Assert.notNull(pageable, "Pageable must not be null!");
        Assert.notNull(totalSupplier, "TotalSupplier must not be null!");

        if (pageable.isUnpaged() || pageable.getOffset() == 0) {

            if (pageable.isUnpaged() || pageable.getPageSize() > content.size()) {
                return new PageImpl<>(content, pageable, content.size());
            }

            return new PageImpl<>(content, pageable, totalSupplier.getAsLong());
        }

        if (content.size() != 0 && pageable.getPageSize() > content.size()) {
            return new PageImpl<>(content, pageable, pageable.getOffset() + content.size());
        }

        return new PageImpl<>(content, pageable, totalSupplier.getAsLong());
    }

jpa生成count語句的邏輯也非常簡單,就是做了一個正則來替換查詢語句,對于我這個查詢,count語句就變成了上面那個樣子,jpa也考慮到這樣生成的sql可能是有問題的,所以@Query注解提供了countQuery屬性,查詢語句比較復(fù)雜的時候可以自己寫一個count語句給jpa使用。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容