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
命令下载到本地或者通过浏览器方式查看源代码。
网友评论