jpa使用@Query自定义分页查询报错You have an error in your SQL syntax; check the manual that corresponds t...

因为业务需要一个分页查询的列表,但是对数据内容有去重的需求,简单了解了JPA的@Query注解使用方式后就直接用了自定义sql来做,测试通过后上线测了两笔也没问题就没太在意。但是隔了一天运营就反应说功能报错了,而且我去看日志发现报错很奇怪,是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在结果集那里是没有括号的

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

这个括号是如何生成的呢,经过反复的测试样本测试之后发现,这个是jpa在做分页需要查询总数量的时候自动加了一个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 debug到jpa源码之后,才知道jpa在执行分页查询的时候有对记录总数的获取方式做优化,具体实现在org.springframework.data.repository.support.PageableExecutionUtils的getPage方法,jpa就是通过这个方法将结果集封装成page,而其中在计算total的时候会判断当前页偏移量,当前pageSize是否大于查询条件的pageSize,如果能直接计算出来total就不会调用count去数据库查询记录总数

/**
     * 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  Page getPage(List 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属性,查询语句比较复杂的时候可以自己写一个count语句给jpa使用。

你可能感兴趣的:(jpa使用@Query自定义分页查询报错You have an error in your SQL syntax; check the manual that corresponds t...)