美文网首页程序员
JPA框架下实现分页及排序查询

JPA框架下实现分页及排序查询

作者: 梅西爱骑车 | 来源:发表于2020-07-13 17:17 被阅读0次

    JpaRepository<T,ID>,两个变量分别是实体类名字和实体类的主键的类型。
    因为JpaRepository<T,ID>继承PagingAndSortingRepository<T, ID>, CrudRepository<T, ID>,所以封装的就有增删查改功能和分页功能。
    另外一篇类似文章,稍显复杂:https://www.jianshu.com/p/14cd90f32d4d

    一、简单分页查询

    JPA已经实现的分页接口,适用于简单的分页查询。代码实现:

    1.1 POM文件

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <groupId>com.erbadagang.data.jpa</groupId>
        <artifactId>jpa</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <name>jpa</name>
        <description>JPA project for Spring Boot</description>
    
        <properties>
            <java.version>1.8</java.version>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
            <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
            <spring-boot.version>2.3.0.RELEASE</spring-boot.version>
        </properties>
    
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-data-jdbc</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-data-jpa</artifactId>
            </dependency>
            <!--MySQL数据库连接-->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <scope>runtime</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
                <exclusions>
                    <exclusion>
                        <groupId>org.junit.vintage</groupId>
                        <artifactId>junit-vintage-engine</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>1.18.12</version>
            </dependency>
        </dependencies>
    
        <dependencyManagement>
            <dependencies>
                <dependency>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-dependencies</artifactId>
                    <version>${spring-boot.version}</version>
                    <type>pom</type>
                    <scope>import</scope>
                </dependency>
            </dependencies>
        </dependencyManagement>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <configuration>
                        <source>1.8</source>
                        <target>1.8</target>
                        <encoding>UTF-8</encoding>
                    </configuration>
                </plugin>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
            </plugins>
        </build>
    
    </project>
    

    1.2 application.properties

    spring.application.name=jpa
    # 应用服务 WEB 访问端口
    server.port=8080
    ####数据库连接池###
    spring.datasource.url=jdbc:mysql://101.133.227.13:3306/orders_1?useSSL=false&useUnicode=true&characterEncoding=UTF-8
    spring.datasource.username=guo
    spring.datasource.password=205010guo
    spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
    

    1.3 UserRepository

    写个接口UserRepository继承JpaRepository,持久层配置。

    package com.erbadagang.data.jpa.repository;
    
    import com.erbadagang.data.jpa.entity.UserEntity;
    import org.springframework.data.domain.Page;
    import org.springframework.data.domain.Pageable;
    import org.springframework.data.jpa.repository.JpaRepository;
    
    /**
     * (User)表数据库访问层
     *
     * @author 郭秀志 jbcode@126.com
     * @since 2020-07-13 11:13:01
     */
    public interface UserRepository extends JpaRepository<UserEntity, Long> {
        
    }
    

    JpaRepository内部已经有好多接口,看到已经继承了分页排序的PagingAndSortingRepository

    public interface JpaRepository<T, ID> extends PagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T> {
        List<T> findAll();
    
        List<T> findAll(Sort var1);
    
        List<T> findAllById(Iterable<ID> var1);
    
        <S extends T> List<S> saveAll(Iterable<S> var1);
    
        void flush();
    
        <S extends T> S saveAndFlush(S var1);
    
        void deleteInBatch(Iterable<T> var1);
    
        void deleteAllInBatch();
    
        T getOne(ID var1);
    
        <S extends T> List<S> findAll(Example<S> var1);
    
        <S extends T> List<S> findAll(Example<S> var1, Sort var2);
    }
    

    简单分页查询正是使用PagingAndSortingRepository中的如下方法Page<T> findAll(Pageable var1)

    @NoRepositoryBean
    public interface PagingAndSortingRepository<T, ID> extends CrudRepository<T, ID> {
        Iterable<T> findAll(Sort var1);
    
        Page<T> findAll(Pageable var1);
    }
    

    1.4 测试代码

    package com.erbadagang.data.jpa;
    
    import com.erbadagang.data.jpa.entity.UserEntity;
    import com.erbadagang.data.jpa.repository.UserRepository;
    import lombok.extern.slf4j.Slf4j;
    import org.junit.jupiter.api.Test;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.data.domain.Page;
    import org.springframework.data.domain.PageRequest;
    import org.springframework.data.domain.Pageable;
    import org.springframework.data.domain.Sort;
    
    /**
     * @description JPA测试用例。
     * @ClassName: JpaApplicationTests
     * @author: 郭秀志 jbcode@126.com
     * @date: 2020/7/13 16:29
     * @Copyright:
     */
    @SpringBootTest
    @Slf4j
    class JpaApplicationTests {
    
        @Autowired
        private UserRepository userRepository;
    
        @Test
        void contextLoads() {
        }
    
        @Test
        void testFindAll() {
            //Jpa 分页查询
            Sort sort = Sort.by(Sort.Direction.DESC, "id"); //通过id进行倒序,id 是Bean 中的变量,不是数据库中的字段(*)
            int page = 0;
            Pageable pageable = PageRequest.of(page, 5, sort);  // page 从 0 开始 ,5是指每个page的条数,这个意思是id排序分页查询,每次查询2个数据
    
            Page<UserEntity> userPage = userRepository.findAll(pageable);
            userPage.forEach(System.out::println);
            log.info("总记录数:" + userPage.getTotalElements());
        }
    }
    
    数据库的11条数据: 全部数据

    运行测试代码,控制台输出的第一页数据:

    UserEntity(id=13, name=弗鲁姆, age=22, email=null, createTime=null, updateTime=null, operator=null, deleteFlag=null, version=null)
    UserEntity(id=12, name=天空车队, age=22, email=null, createTime=null, updateTime=null, operator=null, deleteFlag=null, version=null)
    UserEntity(id=9, name=梅花, age=8, email=look@erbadagang.cn, createTime=2020-07-12 01:03:51.0, updateTime=2020-07-12 01:03:51.0, operator=梅西爱骑车, deleteFlag=0, version=2)
    UserEntity(id=8, name=闪电, age=18, email=specialized@erbadagang.cn, createTime=2020-07-12 00:11:09.0, updateTime=2020-07-12 00:11:09.0, operator=梅西爱骑车, deleteFlag=1, version=null)
    UserEntity(id=7, name=trek, age=28, email=trek@erbadagang.cn, createTime=2020-07-11 14:57:43.0, updateTime=2020-07-11 23:11:53.0, operator=梅西爱骑车, deleteFlag=null, version=null)
    2020-07-13 16:47:33.192  INFO 8060 --- [main] c.e.data.jpa.JpaApplicationTests         : 总记录数:11
    
    

    可以看到,自带的接口findAll(pageable pageable)只有一个分页参数,但是没有带查询参数。

    二、有查询参数分页

    如果我们需要查询某个条件下的分页,对于分页操作,需要使用到 Pageable 参数,需要作为方法的最后一个参数

    2.1 自定义带过滤条件的JPA接口

    package com.erbadagang.data.jpa.repository;
    
    import com.erbadagang.data.jpa.entity.UserEntity;
    import org.springframework.data.domain.Page;
    import org.springframework.data.domain.Pageable;
    import org.springframework.data.jpa.repository.JpaRepository;
    
    /**
     * (User)表数据库访问层
     *
     * @author 郭秀志 jbcode@126.com
     * @since 2020-07-13 11:13:01
     */
    public interface UserRepository extends JpaRepository<UserEntity, Long> {
        //查询某年龄的所有用户数据并分页
        Page<UserEntity> findByAgeLessThan(Integer age, Pageable pageable);
    }
    

    JPA写的方法名称通过关键字来定义功能,但是findByAgeLessThan中并没有带分页关键字,是根据返回的类型自动判断是否分页,我们这里返回类型 Page<UserEntity>
    如果返回类型为Page,则返回的数据是带分页参数的集合,如果返回类型是list,则返回的数据是list集合。

    2.2 测试

    测试用例:

        @Test
        void testFindByAgeLessThanPage() {
            //Jpa 分页查询
            Sort sort = Sort.by(Sort.Direction.DESC, "id"); //通过id进行倒序,id 是Bean 中的变量,不是数据库中的字段(*)
            int page = 0;
            Pageable pageable = PageRequest.of(page, 2, sort);  // page 从 0 开始 ,2是指每个page的大小,这个意思是id排序分页查询,每次查询2个数据
    
            Page<UserEntity> userPage = userRepository.findByAgeLessThan(20, pageable);
            userPage.getContent().forEach(System.out::println);
            log.info("总记录数:" + userPage.getTotalElements());
            log.info("总页数:" + userPage.getTotalPages());
        }
    

    运行测试代码,控制台输出的第一页数据:

    UserEntity(id=9, name=梅花, age=8, email=look@erbadagang.cn, createTime=2020-07-12 01:03:51.0, updateTime=2020-07-12 01:03:51.0, operator=梅西爱骑车, deleteFlag=0, version=2)
    UserEntity(id=8, name=闪电, age=18, email=specialized@erbadagang.cn, createTime=2020-07-12 00:11:09.0, updateTime=2020-07-12 00:11:09.0, operator=梅西爱骑车, deleteFlag=1, version=null)
    2020-07-13 17:03:06.020  INFO 21144 --- [           main] c.e.data.jpa.JpaApplicationTests         : 总记录数:4
    2020-07-13 17:03:06.020  INFO 21144 --- [           main] c.e.data.jpa.JpaApplicationTests         : 总页数:2
    

    结论:JPA是根据返回的类型自动判断是否分页,如果返回类型为Page,则返回的数据是带分页参数的集合

    2.3 稍复杂的条件

    UserRepository新增一个多条件组合的查询并分页方法。

        //查询<某年龄,并且姓名包括某字符串的所有用户数据并分页
        Page<UserEntity> findByAgeLessThanAndNameContains(Integer age, String name, Pageable pageable);
    

    测试代码

    
        @Test
        void testfindByAgeLessThanAndNameContains() {
            //Jpa 分页查询
            Sort sort = Sort.by(Sort.Direction.DESC, "id"); //通过id进行倒序,id 是Bean 中的变量,不是数据库中的字段(*)
            int page = 0;
            Pageable pageable = PageRequest.of(page, 2, sort);  // page 从 0 开始 ,2是指每个page的大小,这个意思是id排序分页查询,每次查询2个数据
    
            Page<UserEntity> userPage = userRepository.findByAgeLessThanAndNameContains(20, "Guo", pageable);
            userPage.getContent().forEach(System.out::println);
            log.info("总记录数:" + userPage.getTotalElements());
            log.info("总页数:" + userPage.getTotalPages());
        }
    

    运行测试代码,控制台输出的第一页数据:

    UserEntity(id=1, name=Guo , age=18, email=trek@erbadagang.com, createTime=null, updateTime=null, operator=null, deleteFlag=null, version=null)
    2020-07-13 17:13:51.212  INFO 484 --- [           main] c.e.data.jpa.JpaApplicationTests         : 总记录数:1
    2020-07-13 17:13:51.212  INFO 484 --- [           main] c.e.data.jpa.JpaApplicationTests         : 总页数:1
    

    2.4 复杂SQL分页

    如果SQL逻辑比较复杂,可以通过自己写@Query注解,而不是通过简单的方法名来实现。如:

      /**
       * 一个参数name,匹配两个查询条件字段(c.firstName=:name or c.lastName=:name)
       * @param name2
       * @Param pageable 分页参数
       * @return
       * 这里Param的值和=:后面的参数匹配,但不需要和方法名对应的参数值对应
       * 这里增加了@QueryHints注解,是给查询添加一些额外的提示, 比如:当前的name值为HINT_COMMENT是在查询的时候带上一些备注信息
       */
      @QueryHints(value = { @QueryHint(name = HINT_COMMENT, value = "a query for pageable")})
      @Query("select c from Customer c where c.firstName=:name or c.lastName=:name")
      Page<Customer> findByName(@Param("name") String name2,Pageable pageable);
    

    底线


    本文源代码使用 Apache License 2.0开源许可协议,可从Gitee代码地址通过git clone命令下载到本地或者通过浏览器方式查看源代码。

    相关文章

      网友评论

        本文标题:JPA框架下实现分页及排序查询

        本文链接:https://www.haomeiwen.com/subject/feqacktx.html