千家信息网

怎么在Spring Boot中正确使用JPA

发表于:2024-11-11 作者:千家信息网编辑
千家信息网最后更新 2024年11月11日,这篇文章将为大家详细讲解有关怎么在Spring Boot中正确使用JPA,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。一 JPA 基础:常见操作1.相关依赖我们需要
千家信息网最后更新 2024年11月11日怎么在Spring Boot中正确使用JPA

这篇文章将为大家详细讲解有关怎么在Spring Boot中正确使用JPA,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。

一 JPA 基础:常见操作

1.相关依赖

我们需要下面这些依赖支持我们完成这部分内容的学习:

                      org.springframework.boot             spring-boot-starter-web                               org.springframework.boot             spring-boot-starter-data-jpa                               mysql             mysql-connector-java             runtime                               org.projectlombok             lombok             true                               org.springframework.boot             spring-boot-starter-test             test              

2.配置数据库连接信息和JPA配置

下面的配置中需要单独说一下 spring.jpa.hibernate.ddl-auto=create这个配置选项。

这个属性常用的选项有四种:

  1. 鸿蒙官方战略合作共建--HarmonyOS技术社区

  2. create:每次重新启动项目都会重新创新表结构,会导致数据丢失

  3. create-drop:每次启动项目创建表结构,关闭项目删除表结构

  4. update:每次启动项目会更新表结构

  5. validate:验证表结构,不对数据库进行任何更改

但是,一定要不要在生产环境使用 ddl 自动生成表结构,一般推荐手写 SQL 语句配合 Flyway 来做这些事情。

spring.datasource.url=jdbc:mysql://localhost:3306/springboot_jpa?useSSL=false&serverTimezone=CTT spring.datasource.username=root spring.datasource.password=123456 # 打印出 sql 语句 spring.jpa.show-sql=true spring.jpa.hibernate.ddl-auto=create spring.jpa.open-in-view=false # 创建的表的 ENGINE 为 InnoDB spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL55Dialect

3.实体类

我们为这个类添加了 @Entity 注解代表它是数据库持久化类,还配置了主键 id。

import lombok.Data; import lombok.NoArgsConstructor;  import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id;  @Entity @Data @NoArgsConstructor public class Person {          @Id     @GeneratedValue(strategy = GenerationType.IDENTITY)     private Long id;     @Column(unique = true)     private String name;     private Integer age;      public Person(String name, Integer age) {         this.name = name;         this.age = age;     }  }

如何检验你是否正确完成了上面 3 步?很简单,运行项目,查看数据如果发现控制台打印出创建表的 sql 语句,并且数据库中表真的被创建出来的话,说明你成功完成前面 3 步。

控制台打印出来的 sql 语句类似下面这样:

drop table if exists person CREATE TABLE `person` (   `id` bigint(20) NOT NULL AUTO_INCREMENT,   `age` int(11) DEFAULT NULL,   `name` varchar(255) DEFAULT NULL,    PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; alter table person add constraint UK_p0wr4vfyr2lyifm8avi67mqw5 unique (name)

4.创建操作数据库的 Repository 接口

@Repository public interface PersonRepository extends JpaRepository { }

首先这个接口加了 @Repository 注解,代表它和数据库操作有关。另外,它继承了 JpaRepository接口,而JpaRepository长这样:

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

这表明我们只要继承了JpaRepository 就具有了 JPA 为我们提供好的增删改查、分页查询以及根据条件查询等方法。

4.1 JPA 自带方法实战

1) 增删改查

1.保存用户到数据库

Person person = new Person("SnailClimb", 23);    personRepository.save(person);

save()方法对应 sql 语句就是:insert into person (age, name) values (23,"snailclimb")

2.根据 id 查找用户

Optional personOptional = personRepository.findById(id);

findById()方法对应 sql 语句就是:select * from person p where p.id = id

3.根据 id 删除用户

personRepository.deleteById(id);

deleteById()方法对应 sql 语句就是:delete from person where id=id

4.更新用户

更新操作也要通过 save()方法来实现,比如:

Person person = new Person("SnailClimb", 23);     Person savedPerson = personRepository.save(person);     // 更新 person 对象的姓名     savedPerson.setName("UpdatedName");     personRepository.save(savedPerson);

在这里 save()方法相当于 sql 语句:update person set name="UpdatedName" where id=id

2) 带条件的查询

下面这些方法是我们根据 JPA 提供的语法自定义的,你需要将下面这些方法写到 PersonRepository 中。

假如我们想要根据 Name 来查找 Person ,你可以这样:

Optional findByName(String name);

如果你想要找到年龄大于某个值的人,你可以这样:

List findByAgeGreaterThan(int age);

4.2 自定义 SQL 语句实战

很多时候我们自定义 sql 语句会非常有用。

根据 name 来查找 Person:

@Query("select p from Person p where p.name = :name")     Optional findByNameCustomeQuery(@Param("name") String name);

Person 部分属性查询,避免 select *操作:

@Query("select p.name from Person p where p.id = :id")     String findPersonNameById(@Param("id") Long id);

根据 id 更新Person name:

@Modifying     @Transactional     @Query("update Person p set p.name = ?1 where p.id = ?2")     void updatePersonNameById(String name, Long id);

4.3 创建异步方法

如果我们需要创建异步方法的话,也比较方便。

异步方法在调用时立即返回,然后会被提交给TaskExecutor执行。当然你也可以选择得出结果后才返回给客户端。如果对 Spring Boot 异步编程感兴趣的话可以看这篇文章:《新手也能看懂的 SpringBoot 异步编程指南》 。

@Async Future findByName(String name);  @Async CompletableFuture findByName(String name);

5.测试类和源代码地址

测试类:

@SpringBootTest @RunWith(SpringRunner.class) public class PersonRepositoryTest {     @Autowired     private PersonRepository personRepository;     private Long id;      /**      * 保存person到数据库      */     @Before     public void setUp() {         assertNotNull(personRepository);         Person person = new Person("SnailClimb", 23);         Person savedPerson = personRepository.saveAndFlush(person);// 更新 person 对象的姓名         savedPerson.setName("UpdatedName");         personRepository.save(savedPerson);          id = savedPerson.getId();     }      /**      * 使用 JPA 自带的方法查找 person      */     @Test     public void should_get_person() {         Optional personOptional = personRepository.findById(id);         assertTrue(personOptional.isPresent());         assertEquals("SnailClimb", personOptional.get().getName());         assertEquals(Integer.valueOf(23), personOptional.get().getAge());          List personList = personRepository.findByAgeGreaterThan(18);         assertEquals(1, personList.size());         // 清空数据库         personRepository.deleteAll();     }      /**      * 自定义 query sql 查询语句查找 person      */      @Test     public void should_get_person_use_custom_query() {         // 查找所有字段         Optional personOptional = personRepository.findByNameCustomeQuery("SnailClimb");         assertTrue(personOptional.isPresent());         assertEquals(Integer.valueOf(23), personOptional.get().getAge());         // 查找部分字段         String personName = personRepository.findPersonNameById(id);         assertEquals("SnailClimb", personName);         System.out.println(id);         // 更新         personRepository.updatePersonNameById("UpdatedName", id);         Optional updatedName = personRepository.findByNameCustomeQuery("UpdatedName");         assertTrue(updatedName.isPresent());         // 清空数据库         personRepository.deleteAll();     }  }

源代码地址:https://github.com/Snailclimb/springboot-guide/tree/master/source-code/basis/jpa-demo

6. 总结

本文主要介绍了 JPA 的基本用法:

使用 JPA 自带的方法进行增删改查以及条件查询。

自定义 SQL 语句进行查询或者更新数据库。

创建异步的方法。

在下一篇关于 JPA 的文章中我会介绍到非常重要的两个知识点:

基本分页功能实现

多表联合查询以及多表联合查询下的分页功能实现。

二 JPA 连表查询和分页

对于连表查询,在 JPA 中还是非常常见的,由于 JPA 可以在 respository 层自定义 SQL 语句,所以通过自定义 SQL 语句的方式实现连表还是挺简单。这篇文章是在上一篇入门 JPA的文章的基础上写的,不了解 JPA 的可以先看上一篇文章。

在上一节的基础上我们新建了两个实体类,如下:

1.相关实体类创建

Company.java @Entity @Data @NoArgsConstructor public class Company {     @Id     @GeneratedValue(strategy = GenerationType.IDENTITY)     private Long id;     @Column(unique = true)     private String companyName;     private String description;      public Company(String name, String description) {         this.companyName = name;         this.description = description;     } } School.java @Entity @Data @NoArgsConstructor @AllArgsConstructor public class School {     @Id     @GeneratedValue(strategy = GenerationType.IDENTITY)     private Long id;     @Column(unique = true)     private String name;     private String description; }

2.自定义 SQL语句实现连表查询

假如我们当前要通过 person 表的 id 来查询 Person 的话,我们知道 Person 的信息一共分布在Company、School、Person这三张表中,所以,我们如果要把 Person 的信息都查询出来的话是需要进行连表查询的。

首先我们需要创建一个包含我们需要的 Person 信息的 DTO 对象,我们简单第将其命名为 UserDTO,用于保存和传输我们想要的信息。

@Data @NoArgsConstructor @Builder(toBuilder = true) @AllArgsConstructor public class UserDTO {     private String name;     private int age;     private String companyName;     private String schoolName; }

下面我们就来写一个方法查询出 Person 的基本信息。

/**    * 连表查询    */   @Query(value = "select new github.snailclimb.jpademo.model.dto.UserDTO(p.name,p.age,c.companyName,s.name) " +           "from Person p left join Company c on  p.companyId=c.id " +           "left join School s on p.schoolId=s.id " +           "where p.id=:personId")   Optional getUserInformation(@Param("personId") Long personId);

可以看出上面的 sql 语句和我们平时写的没啥区别,差别比较大的就是里面有一个 new 对象的操作。

3.自定义 SQL 语句连表查询并实现分页操作

假如我们要查询当前所有的人员信息并实现分页的话,你可以按照下面这种方式来做。可以看到,为了实现分页,我们在@Query注解中还添加了 countQuery 属性。

@Query(value = "select new github.snailclimb.jpademo.model.dto.UserDTO(p.name,p.age,c.companyName,s.name) " +         "from Person p left join Company c on  p.companyId=c.id " +         "left join School s on p.schoolId=s.id ",         countQuery = "select count(p.id) " +                 "from Person p left join Company c on  p.companyId=c.id " +                 "left join School s on p.schoolId=s.id ") Page getUserInformationList(Pageable pageable);

实际使用:

//分页选项 PageRequest pageRequest = PageRequest.of(0, 3, Sort.Direction.DESC, "age"); Page userInformationList = personRepository.getUserInformationList(pageRequest); //查询结果总数 System.out.println(userInformationList.getTotalElements());// 6 //按照当前分页大小,总页数 System.out.println(userInformationList.getTotalPages());// 2 System.out.println(userInformationList.getContent());

4.加餐:自定以SQL语句的其他用法

下面我只介绍两种比较常用的:

IN 查询

BETWEEN 查询

当然,还有很多用法需要大家自己去实践了。

4.1 IN 查询

在 sql 语句中加入我们需要筛选出符合几个条件中的一个的情况下,可以使用 IN 查询,对应到 JPA 中也非常简单。比如下面的方法就实现了,根据名字过滤需要的人员信息。

@Query(value = "select new github.snailclimb.jpademo.model.dto.UserDTO(p.name,p.age,c.companyName,s.name) " +         "from Person p left join Company c on  p.companyId=c.id " +         "left join School s on p.schoolId=s.id " +         "where p.name IN :peopleList") List filterUserInfo(List peopleList);

实际使用:

List personList=new ArrayList<>(Arrays.asList("person1","person2"));List userDTOS = personRepository.filterUserInfo(personList);

4.2 BETWEEN 查询

查询满足某个范围的值。比如下面的方法就实现查询满足某个年龄范围的人员的信息。

@Query(value = "select new github.snailclimb.jpademo.model.dto.UserDTO(p.name,p.age,c.companyName,s.name) " +             "from Person p left join Company c on  p.companyId=c.id " +             "left join School s on p.schoolId=s.id " +             "where p.age between :small and :big")     List filterUserInfoByAge(int small,int big);

实际使用:

List userDTOS = personRepository.filterUserInfoByAge(19,20);

5.测试类和源代码地址

@SpringBootTest @RunWith(SpringRunner.class) public class PersonRepositoryTest2 {     @Autowired     private PersonRepository personRepository;      @Sql(scripts = {"classpath:/init.sql"})     @Test     public void find_person_age_older_than_18() {         List personList = personRepository.findByAgeGreaterThan(18);         assertEquals(1, personList.size());     }      @Sql(scripts = {"classpath:/init.sql"})     @Test     public void should_get_user_info() {         Optional userInformation = personRepository.getUserInformation(1L);         System.out.println(userInformation.get().toString());     }      @Sql(scripts = {"classpath:/init.sql"})     @Test     public void should_get_user_info_list() {         PageRequest pageRequest = PageRequest.of(0, 3, Sort.Direction.DESC, "age");         Page userInformationList = personRepository.getUserInformationList(pageRequest);         //查询结果总数         System.out.println(userInformationList.getTotalElements());// 6         //按照当前分页大小,总页数         System.out.println(userInformationList.getTotalPages());// 2         System.out.println(userInformationList.getContent());     }      @Sql(scripts = {"classpath:/init.sql"})     @Test     public void should_filter_user_info() {         List personList=new ArrayList<>(Arrays.asList("person1","person2"));         List userDTOS = personRepository.filterUserInfo(personList);         System.out.println(userDTOS);     }      @Sql(scripts = {"classpath:/init.sql"})     @Test     public void should_filter_user_info_by_age() {         List userDTOS = personRepository.filterUserInfoByAge(19,20);         System.out.println(userDTOS);     } }

关于"怎么在Spring Boot中正确使用JPA"这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,使各位可以学到更多知识,如果觉得文章不错,请把它分享出去让更多的人看到。

查询 语句 方法 数据 数据库 信息 更新 篇文章 结构 项目 配置 对象 就是 条件 用户 面的 人员 地址 基础 实体 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 网络技术属于电子还是信息 网络安全工作网络舆情 毕业论文中数据库表怎么画 sql数据库时间戳函数 携手共建网络安全什么题 优炫数据库安全管理 思科网络技术设备配置基础考试 网络安全威胁表现 杭州天眼互联网科技有限公司 mysql的数据库题库 软件开发魔典系列书怎么样 网络技术员要学会多久 服务器主机可以带显示屏吗 怎样确定服务器的远程端口 南京银联软件开发答疑解惑 奥丁神叛港服显示服务器太忙 小程序服务器买哪个 网络安全知识竞赛学校 我的世界服务器哪家好 海鹰国际互联网科技有限公司 数据库登录密码为啥可以有几个 软件开发寻他 苹果的流媒体服务器 网络安全知识教育活动口号 辽宁电信服务器地址 杭州用什么招聘软件开发 hfss非匹配网络技术 服务器管理器怎么看谁打开了文件 丽水手机app定制软件开发 无线网络安全配置
0