1. 首页
  2. IT资讯

一文搞懂如何在Spring Boot 正确中使用JPA(值得收藏)

“u003Cdivu003Eu003Cpu003EJPA 这部分内容上手很容易,但是涉及到的东西还是挺多的,网上大部分关于 JPA 的资料都不是特别齐全,大部分用的版本也是比较落后的。另外,我下面讲到了的内容也不可能涵盖所有 JPA 相关内容,我只是把自己觉得比较重要的知识点总结在了下面。很多地方我自己也是参考着官方文档写的,官方文档非常详细了,非常推荐阅读一下。这篇文章可以帮助对 JPA 不了解或者不太熟悉的人来在实际项目中正确使用 JPA。u003Cu002Fpu003Eu003Cpu003E另外,我发现网上关于连表查询这一块并没有太多比较有参考价值的博客,所以对这部分也做了详细的总结,以供大家学习参考u003Cu002Fpu003Eu003Cpu003E项目代码基于 Spring Boot 最新的 2.1.9.RELEASE 版本构建(截止到这篇文章写完),另外,新建项目的过程就不多说了。u003Cu002Fpu003Eu003Ch1u003Eu003Cstrongu003E一 JPA 基础:常见操作u003Cu002Fstrongu003Eu003Cu002Fh1u003Eu003Cpu003Eu003Cstrongu003E1.相关依赖u003Cu002Fstrongu003Eu003Cu002Fpu003Eu003Cpu003E我们需要下面这些依赖支持我们完成这部分内容的学习:u003Cu002Fpu003Eu003Cpreu003E <dependencies>u003Cbru003E <dependency>u003Cbru003E <groupId>org.springframework.boot<u002FgroupId>u003Cbru003E <artifactId>spring-boot-starter-web<u002FartifactId>u003Cbru003E <u002Fdependency>u003Cbru003E <dependency>u003Cbru003E <groupId>org.springframework.boot<u002FgroupId>u003Cbru003E <artifactId>spring-boot-starter-data-jpa<u002FartifactId>u003Cbru003E <u002Fdependency>u003Cbru003E <dependency>u003Cbru003E <groupId>mysql<u002FgroupId>u003Cbru003E <artifactId>mysql-connector-java<u002FartifactId>u003Cbru003E <scope>runtime<u002Fscope>u003Cbru003E <u002Fdependency>u003Cbru003E <dependency>u003Cbru003E <groupId>org.projectlombok<u002FgroupId>u003Cbru003E <artifactId>lombok<u002FartifactId>u003Cbru003E <optional>true<u002Foptional>u003Cbru003E <u002Fdependency>u003Cbru003E <dependency>u003Cbru003E <groupId>org.springframework.boot<u002FgroupId>u003Cbru003E <artifactId>spring-boot-starter-test<u002FartifactId>u003Cbru003E <scope>test<u002Fscope>u003Cbru003E <u002Fdependency>u003Cbru003E <u002Fdependencies>u003Cbru003Eu003Cu002Fpreu003Eu003Cpu003Eu003Cstrongu003E2.配置数据库连接信息和JPA配置u003Cu002Fstrongu003Eu003Cu002Fpu003Eu003Cpu003E下面的配置中需要单独说一下 spring.jpa.hibernate.ddl-auto=create这个配置选项。u003Cu002Fpu003Eu003Cpu003E这个属性常用的选项有四种:u003Cu002Fpu003Eu003Colu003Eu003Cliu003Ecreate:每次重新启动项目都会重新创新表结构,会导致数据丢失u003Cu002Fliu003Eu003Cliu003Ecreate-drop:每次启动项目创建表结构,关闭项目删除表结构u003Cu002Fliu003Eu003Cliu003Eupdate:每次启动项目会更新表结构u003Cu002Fliu003Eu003Cliu003Evalidate:验证表结构,不对数据库进行任何更改u003Cu002Fliu003Eu003Cu002Folu003Eu003Cpu003E但是,u003Cstrongu003E一定要不要在生产环境使用 ddl 自动生成表结构,一般推荐手写 SQL 语句配合 Flyway 来做这些事情。u003Cu002Fstrongu003Eu003Cu002Fpu003Eu003Cpreu003Espring.datasource.url=jdbc:mysql:u002Fu002Flocalhost:3306u002Fspringboot_jpa?useSSL=false&serverTimezone=CTTu003Cbru003Espring.datasource.username=rootu003Cbru003Espring.datasource.password=123456u003Cbru003E# 打印出 sql 语句u003Cbru003Espring.jpa.show-sql=trueu003Cbru003Espring.jpa.hibernate.ddl-auto=createu003Cbru003Espring.jpa.open-in-view=falseu003Cbru003E# 创建的表的 ENGINE 为 InnoDBu003Cbru003Espring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL55Dialectu003Cbru003Eu003Cu002Fpreu003Eu003Cpu003Eu003Cstrongu003E3.实体类u003Cu002Fstrongu003Eu003Cu002Fpu003Eu003Cpu003E我们为这个类添加了 @Entity 注解代表它是数据库持久化类,还配置了主键 id。u003Cu002Fpu003Eu003Cpreu003Eimport lombok.Data;u003Cbru003Eimport lombok.NoArgsConstructor;u003Cbru003Eimport javax.persistence.Column;u003Cbru003Eimport javax.persistence.Entity;u003Cbru003Eimport javax.persistence.GeneratedValue;u003Cbru003Eimport javax.persistence.GenerationType;u003Cbru003Eimport javax.persistence.Id;u003Cbru003E@Entityu003Cbru003E@Datau003Cbru003E@NoArgsConstructoru003Cbru003Epublic class Person {u003Cbru003E u003Cbru003E @Idu003Cbru003E @GeneratedValue(strategy = GenerationType.IDENTITY)u003Cbru003E private Long id;u003Cbru003E @Column(unique = true)u003Cbru003E private String name;u003Cbru003E private Integer age;u003Cbru003E public Person(String name, Integer age) {u003Cbru003E this.name = name;u003Cbru003E this.age = age;u003Cbru003E }u003Cbru003E}u003Cbru003Eu003Cu002Fpreu003Eu003Cpu003E如何检验你是否正确完成了上面 3 步?很简单,运行项目,查看数据如果发现控制台打印出创建表的 sql 语句,并且数据库中表真的被创建出来的话,说明你成功完成前面 3 步。u003Cu002Fpu003Eu003Cpu003E控制台打印出来的 sql 语句类似下面这样:u003Cu002Fpu003Eu003Cpreu003Edrop table if exists personu003Cbru003ECREATE TABLE `person` (u003Cbru003E `id` bigint(20) NOT NULL AUTO_INCREMENT,u003Cbru003E `age` int(11) DEFAULT NULL,u003Cbru003E `name` varchar(255) DEFAULT NULL,u003Cbru003E PRIMARY KEY (`id`)u003Cbru003E) ENGINE=InnoDB DEFAULT CHARSET=utf8;u003Cbru003Ealter table person add constraint UK_p0wr4vfyr2lyifm8avi67mqw5 unique (name)u003Cbru003Eu003Cu002Fpreu003Eu003Cpu003Eu003Cstrongu003E4.创建操作数据库的 Repository 接口u003Cu002Fstrongu003Eu003Cu002Fpu003Eu003Cpreu003E@Repositoryu003Cbru003Epublic interface PersonRepository extends JpaRepository<Person, Long> {u003Cbru003E}u003Cbru003Eu003Cu002Fpreu003Eu003Cpu003E首先这个接口加了 @Repository 注解,代表它和数据库操作有关。另外,它继承了 JpaRepository<Person, Long>接口,而JpaRepository<Person, Long>长这样:u003Cu002Fpu003Eu003Cpreu003Eu003Cbru003E@NoRepositoryBeanu003Cbru003Epublic interface JpaRepository<T, ID> extends PagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T> {u003Cbru003E List<T> findAll();u003Cbru003E List<T> findAll(Sort var1);u003Cbru003E List<T> findAllById(Iterable<ID> var1);u003Cbru003E <S extends T> List<S> saveAll(Iterable<S> var1);u003Cbru003E void flush();u003Cbru003E <S extends T> S saveAndFlush(S var1);u003Cbru003E void deleteInBatch(Iterable<T> var1);u003Cbru003E void deleteAllInBatch();u003Cbru003E T getOne(ID var1);u003Cbru003E <S extends T> List<S> findAll(Example<S> var1);u003Cbru003E <S extends T> List<S> findAll(Example<S> var1, Sort var2);u003Cbru003E}u003Cbru003Eu003Cu002Fpreu003Eu003Cpu003E这表明我们只要继承了JpaRepository<T, ID> 就具有了 JPA 为我们提供好的增删改查、分页查询以及根据条件查询等方法。u003Cu002Fpu003Eu003Cpu003Eu003Cstrongu003E4.1 JPA 自带方法实战u003Cu002Fstrongu003Eu003Cu002Fpu003Eu003Cpu003Eu003Cstrongu003E1) 增删改查u003Cu002Fstrongu003Eu003Cu002Fpu003Eu003Cpu003Eu003Cstrongu003E1.保存用户到数据库u003Cu002Fstrongu003Eu003Cu002Fpu003Eu003Cpreu003E Person person = new Person(“SnailClimb”, 23);u003Cbru003E personRepository.save(person);u003Cbru003Eu003Cu002Fpreu003Eu003Cpu003Esave()方法对应 sql 语句就是:insert into person (age, name) values (23,”snailclimb”)u003Cu002Fpu003Eu003Cpu003Eu003Cstrongu003E2.根据 id 查找用户u003Cu002Fstrongu003Eu003Cu002Fpu003Eu003Cpreu003E Optional<Person> personOptional = personRepository.findById(id);u003Cbru003Eu003Cu002Fpreu003Eu003Cpu003EfindById()方法对应 sql 语句就是:select * from person p where p.id = idu003Cu002Fpu003Eu003Cpu003Eu003Cstrongu003E3.根据 id 删除用户u003Cu002Fstrongu003Eu003Cu002Fpu003Eu003Cpreu003E personRepository.deleteById(id);u003Cbru003Eu003Cu002Fpreu003Eu003Cpu003EdeleteById()方法对应 sql 语句就是:delete from person where id=idu003Cu002Fpu003Eu003Cpu003Eu003Cstrongu003E4.更新用户u003Cu002Fstrongu003Eu003Cu002Fpu003Eu003Cpu003E更新操作也要通过 save()方法来实现,比如:u003Cu002Fpu003Eu003Cpreu003E Person person = new Person(“SnailClimb”, 23);u003Cbru003E Person savedPerson = personRepository.save(person);u003Cbru003E u002Fu002F 更新 person 对象的姓名u003Cbru003E savedPerson.setName(“UpdatedName”);u003Cbru003E personRepository.save(savedPerson);u003Cbru003Eu003Cu002Fpreu003Eu003Cpu003E在这里 save()方法相当于 sql 语句:update person set name=”UpdatedName” where id=idu003Cu002Fpu003Eu003Cpu003Eu003Cstrongu003E2) 带条件的查询u003Cu002Fstrongu003Eu003Cu002Fpu003Eu003Cpu003E下面这些方法是我们根据 JPA 提供的语法自定义的,你需要将下面这些方法写到PersonRepository 中。u003Cu002Fpu003Eu003Cpu003E假如我们想要根据 Name 来查找 Person ,你可以这样:u003Cu002Fpu003Eu003Cpreu003E Optional<Person> findByName(String name);u003Cbru003Eu003Cu002Fpreu003Eu003Cpu003E如果你想要找到年龄大于某个值的人,你可以这样:u003Cu002Fpu003Eu003Cpreu003E List<Person> findByAgeGreaterThan(int age);u003Cbru003Eu003Cu002Fpreu003Eu003Cpu003Eu003Cstrongu003E4.2 自定义 SQL 语句实战u003Cu002Fstrongu003Eu003Cu002Fpu003Eu003Cpu003E很多时候我们自定义 sql 语句会非常有用。u003Cu002Fpu003Eu003Cpu003E根据 name 来查找 Person:u003Cu002Fpu003Eu003Cpreu003E @Query(“select p from Person p where p.name = :name”)u003Cbru003E Optional<Person> findByNameCustomeQuery(@Param(“name”) String name);u003Cbru003Eu003Cu002Fpreu003Eu003Cpu003EPerson 部分属性查询,避免 select *操作:u003Cu002Fpu003Eu003Cpreu003E @Query(“select p.name from Person p where p.id = :id”)u003Cbru003E String findPersonNameById(@Param(“id”) Long id);u003Cbru003Eu003Cu002Fpreu003Eu003Cpu003E根据 id 更新Person name:u003Cu002Fpu003Eu003Cpreu003Eu003Cbru003E @Modifyingu003Cbru003E @Transactionalu003Cbru003E @Query(“update Person p set p.name = ?1 where p.id = ?2”)u003Cbru003E void updatePersonNameById(String name, Long id);u003Cbru003Eu003Cu002Fpreu003Eu003Cpu003Eu003Cstrongu003E4.3 创建异步方法u003Cu002Fstrongu003Eu003Cu002Fpu003Eu003Cpu003E如果我们需要创建异步方法的话,也比较方便。u003Cu002Fpu003Eu003Cpu003E异步方法在调用时立即返回,然后会被提交给TaskExecutor执行。当然你也可以选择得出结果后才返回给客户端。如果对 Spring Boot 异步编程感兴趣的话可以看这篇文章:《新手也能看懂的 SpringBoot 异步编程指南》 。u003Cu002Fpu003Eu003Cpreu003E@Asyncu003Cbru003EFuture<User> findByName(String name);u003Cbru003E@Asyncu003Cbru003ECompletableFuture<User> findByName(String name);u003Cbru003Eu003Cu002Fpreu003Eu003Cpu003Eu003Cstrongu003E5.测试类和源代码地址u003Cu002Fstrongu003Eu003Cu002Fpu003Eu003Cpu003E测试类:u003Cu002Fpu003Eu003Cpreu003Eu003Cbru003E@SpringBootTestu003Cbru003E@RunWith(SpringRunner.class)u003Cbru003Epublic class PersonRepositoryTest {u003Cbru003E @Autowiredu003Cbru003E private PersonRepository personRepository;u003Cbru003E private Long id;u003Cbru003E u002F**u003Cbru003E * 保存person到数据库u003Cbru003E *u002Fu003Cbru003E @Beforeu003Cbru003E public void setUp() {u003Cbru003E assertNotNull(personRepository);u003Cbru003E Person person = new Person(“SnailClimb”, 23);u003Cbru003E Person savedPerson = personRepository.saveAndFlush(person);u002Fu002F 更新 person 对象的姓名u003Cbru003E savedPerson.setName(“UpdatedName”);u003Cbru003E personRepository.save(savedPerson);u003Cbru003E id = savedPerson.getId();u003Cbru003E }u003Cbru003E u002F**u003Cbru003E * 使用 JPA 自带的方法查找 personu003Cbru003E *u002Fu003Cbru003E @Testu003Cbru003E public void should_get_person() {u003Cbru003E Optional<Person> personOptional = personRepository.findById(id);u003Cbru003E assertTrue(personOptional.isPresent());u003Cbru003E assertEquals(“SnailClimb”, personOptional.get().getName());u003Cbru003E assertEquals(Integer.valueOf(23), personOptional.get().getAge());u003Cbru003E List<Person> personList = personRepository.findByAgeGreaterThan(18);u003Cbru003E assertEquals(1, personList.size());u003Cbru003E u002Fu002F 清空数据库u003Cbru003E personRepository.deleteAll();u003Cbru003E }u003Cbru003E u002F**u003Cbru003E * 自定义 query sql 查询语句查找 personu003Cbru003E *u002Fu003Cbru003E @Testu003Cbru003E public void should_get_person_use_custom_query() {u003Cbru003E u002Fu002F 查找所有字段u003Cbru003E Optional<Person> personOptional = personRepository.findByNameCustomeQuery(“SnailClimb”);u003Cbru003E assertTrue(personOptional.isPresent());u003Cbru003E assertEquals(Integer.valueOf(23), personOptional.get().getAge());u003Cbru003E u002Fu002F 查找部分字段u003Cbru003E String personName = personRepository.findPersonNameById(id);u003Cbru003E assertEquals(“SnailClimb”, personName);u003Cbru003E System.out.println(id);u003Cbru003E u002Fu002F 更新u003Cbru003E personRepository.updatePersonNameById(“UpdatedName”, id);u003Cbru003E Optional<Person> updatedName = personRepository.findByNameCustomeQuery(“UpdatedName”);u003Cbru003E assertTrue(updatedName.isPresent());u003Cbru003E u002Fu002F 清空数据库u003Cbru003E personRepository.deleteAll();u003Cbru003E }u003Cbru003E}u003Cbru003Eu003Cu002Fpreu003Eu003Cpu003E源代码地址:u003Cstrongu003Ehttps:u002Fu002Fgithub.comu002FSnailclimbu002Fspringboot-guideu002Ftreeu002Fmasteru002Fsource-codeu002Fbasisu002Fjpa-demou003Cu002Fstrongu003Eu003Cu002Fpu003Eu003Cpu003Eu003Cstrongu003E6. 总结u003Cu002Fstrongu003Eu003Cu002Fpu003Eu003Cpu003E本文主要介绍了 JPA 的基本用法:u003Cu002Fpu003Eu003Colu003Eu003Cliu003E使用 JPA 自带的方法进行增删改查以及条件查询。u003Cu002Fliu003Eu003Cliu003E自定义 SQL 语句进行查询或者更新数据库。u003Cu002Fliu003Eu003Cliu003E创建异步的方法。u003Cu002Fliu003Eu003Cu002Folu003Eu003Cpu003E在下一篇关于 JPA 的文章中我会介绍到非常重要的两个知识点:u003Cu002Fpu003Eu003Colu003Eu003Cliu003E基本分页功能实现u003Cu002Fliu003Eu003Cliu003E多表联合查询以及多表联合查询下的分页功能实现。u003Cu002Fliu003Eu003Cu002Folu003Eu003Ch1u003Eu003Cstrongu003E二 JPA 连表查询和分页u003Cu002Fstrongu003Eu003Cu002Fh1u003Eu003Cpu003E对于连表查询,在 JPA 中还是非常常见的,由于 JPA 可以在 respository 层自定义 SQL 语句,所以通过自定义 SQL 语句的方式实现连表还是挺简单。这篇文章是在上一篇入门 JPA的文章的基础上写的,不了解 JPA 的可以先看上一篇文章。u003Cu002Fpu003Eu003Cpu003E在上一节的基础上我们新建了两个实体类,如下:u003Cu002Fpu003Eu003Cpu003Eu003Cstrongu003E1.相关实体类创建u003Cu002Fstrongu003Eu003Cu002Fpu003Eu003Cpu003ECompany.javau003Cu002Fpu003Eu003Cpreu003E@Entityu003Cbru003E@Datau003Cbru003E@NoArgsConstructoru003Cbru003Epublic class Company {u003Cbru003E @Idu003Cbru003E @GeneratedValue(strategy = GenerationType.IDENTITY)u003Cbru003E private Long id;u003Cbru003E @Column(unique = true)u003Cbru003E private String companyName;u003Cbru003E private String description;u003Cbru003E public Company(String name, String description) {u003Cbru003E this.companyName = name;u003Cbru003E this.description = description;u003Cbru003E }u003Cbru003E}u003Cbru003Eu003Cu002Fpreu003Eu003Cpu003ESchool.javau003Cu002Fpu003Eu003Cpreu003E@Entityu003Cbru003E@Datau003Cbru003E@NoArgsConstructoru003Cbru003E@AllArgsConstructoru003Cbru003Epublic class School {u003Cbru003E @Idu003Cbru003E @GeneratedValue(strategy = GenerationType.IDENTITY)u003Cbru003E private Long id;u003Cbru003E @Column(unique = true)u003Cbru003E private String name;u003Cbru003E private String description;u003Cbru003E}u003Cbru003Eu003Cu002Fpreu003Eu003Cpu003Eu003Cstrongu003E2.自定义 SQL语句实现连表查询u003Cu002Fstrongu003Eu003Cu002Fpu003Eu003Cpu003E假如我们当前要通过 person 表的 id 来查询 Person 的话,我们知道 Person 的信息一共分布在Company、School、Person这三张表中,所以,我们如果要把 Person 的信息都查询出来的话是需要进行连表查询的。u003Cu002Fpu003Eu003Cpu003E首先我们需要创建一个包含我们需要的 Person 信息的 DTO 对象,我们简单第将其命名为 UserDTO,用于保存和传输我们想要的信息。u003Cu002Fpu003Eu003Cpreu003E@Datau003Cbru003E@NoArgsConstructoru003Cbru003E@Builder(toBuilder = true)u003Cbru003E@AllArgsConstructoru003Cbru003Epublic class UserDTO {u003Cbru003E private String name;u003Cbru003E private int age;u003Cbru003E private String companyName;u003Cbru003E private String schoolName;u003Cbru003E}u003Cbru003Eu003Cu002Fpreu003Eu003Cpu003E下面我们就来写一个方法查询出 Person 的基本信息。u003Cu002Fpu003Eu003Cpreu003E u002F**u003Cbru003E * 连表查询u003Cbru003E *u002Fu003Cbru003E @Query(value = “select new github.snailclimb.jpademo.model.dto.UserDTO(p.name,p.age,c.companyName,s.name) ” +u003Cbru003E “from Person p left join Company c on p.companyId=c.id ” +u003Cbru003E “left join School s on p.schoolId=s.id ” +u003Cbru003E “where p.id=:personId”)u003Cbru003E Optional<UserDTO> getUserInformation(@Param(“personId”) Long personId);u003Cbru003Eu003Cu002Fpreu003Eu003Cpu003E可以看出上面的 sql 语句和我们平时写的没啥区别,差别比较大的就是里面有一个 new 对象的操作。u003Cu002Fpu003Eu003Cpu003Eu003Cstrongu003E3.自定义 SQL 语句连表查询并实现分页操作u003Cu002Fstrongu003Eu003Cu002Fpu003Eu003Cpu003E假如我们要查询当前所有的人员信息并实现分页的话,你可以按照下面这种方式来做。可以看到,为了实现分页,我们在@Query注解中还添加了 u003Cstrongu003EcountQueryu003Cu002Fstrongu003E 属性。u003Cu002Fpu003Eu003Cpreu003E@Query(value = “select new github.snailclimb.jpademo.model.dto.UserDTO(p.name,p.age,c.companyName,s.name) ” +u003Cbru003E “from Person p left join Company c on p.companyId=c.id ” +u003Cbru003E “left join School s on p.schoolId=s.id “,u003Cbru003E countQuery = “select count(p.id) ” +u003Cbru003E “from Person p left join Company c on p.companyId=c.id ” +u003Cbru003E “left join School s on p.schoolId=s.id “)u003Cbru003EPage<UserDTO> getUserInformationList(Pageable pageable);u003Cbru003Eu003Cu002Fpreu003Eu003Cpu003E实际使用:u003Cu002Fpu003Eu003Cpreu003Eu002Fu002F分页选项u003Cbru003EPageRequest pageRequest = PageRequest.of(0, 3, Sort.Direction.DESC, “age”);u003Cbru003EPage<UserDTO> userInformationList = personRepository.getUserInformationList(pageRequest);u003Cbru003Eu002Fu002F查询结果总数u003Cbru003ESystem.out.println(userInformationList.getTotalElements());u002Fu002F 6u003Cbru003Eu002Fu002F按照当前分页大小,总页数u003Cbru003ESystem.out.println(userInformationList.getTotalPages());u002Fu002F 2u003Cbru003ESystem.out.println(userInformationList.getContent());u003Cbru003Eu003Cu002Fpreu003Eu003Cpu003Eu003Cstrongu003E4.加餐:自定以SQL语句的其他用法u003Cu002Fstrongu003Eu003Cu002Fpu003Eu003Cpu003E下面我只介绍两种比较常用的:u003Cu002Fpu003Eu003Colu003Eu003Cliu003EIN 查询u003Cu002Fliu003Eu003Cliu003EBETWEEN 查询u003Cu002Fliu003Eu003Cu002Folu003Eu003Cpu003E当然,还有很多用法需要大家自己去实践了。u003Cu002Fpu003Eu003Cpu003Eu003Cstrongu003E4.1 IN 查询u003Cu002Fstrongu003Eu003Cu002Fpu003Eu003Cpu003E在 sql 语句中加入我们需要筛选出符合几个条件中的一个的情况下,可以使用 IN 查询,对应到 JPA 中也非常简单。比如下面的方法就实现了,根据名字过滤需要的人员信息。u003Cu002Fpu003Eu003Cpreu003E@Query(value = “select new github.snailclimb.jpademo.model.dto.UserDTO(p.name,p.age,c.companyName,s.name) ” +u003Cbru003E “from Person p left join Company c on p.companyId=c.id ” +u003Cbru003E “left join School s on p.schoolId=s.id ” +u003Cbru003E “where p.name IN :peopleList”)u003Cbru003EList<UserDTO> filterUserInfo(List peopleList);u003Cbru003Eu003Cu002Fpreu003Eu003Cpu003E实际使用:u003Cu002Fpu003Eu003Cpreu003EList<String> personList=new ArrayList<>(Arrays.asList(“person1″,”person2”));u003Cbru003EList<UserDTO> userDTOS = personRepository.filterUserInfo(personList);u003Cbru003Eu003Cu002Fpreu003Eu003Cpu003Eu003Cstrongu003E4.2 BETWEEN 查询u003Cu002Fstrongu003Eu003Cu002Fpu003Eu003Cpu003E查询满足某个范围的值。比如下面的方法就实现查询满足某个年龄范围的人员的信息。u003Cu002Fpu003Eu003Cpreu003E @Query(value = “select new github.snailclimb.jpademo.model.dto.UserDTO(p.name,p.age,c.companyName,s.name) ” +u003Cbru003E “from Person p left join Company c on p.companyId=c.id ” +u003Cbru003E “left join School s on p.schoolId=s.id ” +u003Cbru003E “where p.age between :small and :big”)u003Cbru003E List<UserDTO> filterUserInfoByAge(int small,int big);u003Cbru003Eu003Cu002Fpreu003Eu003Cpu003E实际使用:u003Cu002Fpu003Eu003Cpreu003EList<UserDTO> userDTOS = personRepository.filterUserInfoByAge(19,20);u003Cbru003Eu003Cu002Fpreu003Eu003Cpu003Eu003Cstrongu003E5.测试类和源代码地址u003Cu002Fstrongu003Eu003Cu002Fpu003Eu003Cpreu003E@SpringBootTestu003Cbru003E@RunWith(SpringRunner.class)u003Cbru003Epublic class PersonRepositoryTest2 {u003Cbru003E @Autowiredu003Cbru003E private PersonRepository personRepository;u003Cbru003E @Sql(scripts = {“classpath:u002Finit.sql”})u003Cbru003E @Testu003Cbru003E public void find_person_age_older_than_18() {u003Cbru003E List<Person> personList = personRepository.findByAgeGreaterThan(18);u003Cbru003E assertEquals(1, personList.size());u003Cbru003E }u003Cbru003E @Sql(scripts = {“classpath:u002Finit.sql”})u003Cbru003E @Testu003Cbru003E public void should_get_user_info() {u003Cbru003E Optional<UserDTO> userInformation = personRepository.getUserInformation(1L);u003Cbru003E System.out.println(userInformation.get().toString());u003Cbru003E }u003Cbru003E @Sql(scripts = {“classpath:u002Finit.sql”})u003Cbru003E @Testu003Cbru003E public void should_get_user_info_list() {u003Cbru003E PageRequest pageRequest = PageRequest.of(0, 3, Sort.Direction.DESC, “age”);u003Cbru003E Page<UserDTO> userInformationList = personRepository.getUserInformationList(pageRequest);u003Cbru003E u002Fu002F查询结果总数u003Cbru003E System.out.println(userInformationList.getTotalElements());u002Fu002F 6u003Cbru003E u002Fu002F按照当前分页大小,总页数u003Cbru003E System.out.println(userInformationList.getTotalPages());u002Fu002F 2u003Cbru003E System.out.println(userInformationList.getContent());u003Cbru003E }u003Cbru003E @Sql(scripts = {“classpath:u002Finit.sql”})u003Cbru003E @Testu003Cbru003E public void should_filter_user_info() {u003Cbru003E List<String> personList=new ArrayList<>(Arrays.asList(“person1″,”person2”));u003Cbru003E List<UserDTO> userDTOS = personRepository.filterUserInfo(personList);u003Cbru003E System.out.println(userDTOS);u003Cbru003E }u003Cbru003E @Sql(scripts = {“classpath:u002Finit.sql”})u003Cbru003E @Testu003Cbru003E public void should_filter_user_info_by_age() {u003Cbru003E List<UserDTO> userDTOS = personRepository.filterUserInfoByAge(19,20);u003Cbru003E System.out.println(userDTOS);u003Cbru003E }u003Cbru003E}u003Cbru003Eu003Cu002Fpreu003Eu003Cpu003Eu003Cstrongu003E六 总结u003Cu002Fstrongu003Eu003Cu002Fpu003Eu003Cpu003E本节我们主要学习了下面几个知识点:u003Cu002Fpu003Eu003Colu003Eu003Cliu003E自定义 SQL 语句实现连表查询;u003Cu002Fliu003Eu003Cliu003E自定义 SQL 语句连表查询并实现分页操作;u003Cu002Fliu003Eu003Cliu003E条件查询:IN 查询,BETWEEN查询。u003Cu002Fliu003Eu003Cu002Folu003Eu003Cpu003E我们这一节是把 SQl 语句连表查询的逻辑放在 Dao 层直接写的,这样写的好处是比较方便,也比较简单明了。但是可能会不太好维护,很多时候我们会选择将这些逻辑放到 Service 层去做,这样也是可以实现的,后面章我就会介绍到如何将这些写在 Dao 层的逻辑转移到 Service 层去。u003Cu002Fpu003Eu003Cu002Fdivu003E”

原文始发于:一文搞懂如何在Spring Boot 正确中使用JPA(值得收藏)

主题测试文章,只做测试使用。发布者:逗乐男神i,转转请注明出处:http://www.cxybcw.com/26486.html

联系我们

13687733322

在线咨询:点击这里给我发消息

邮件:1877088071@qq.com

工作时间:周一至周五,9:30-18:30,节假日休息

QR code