溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

怎么在Spring Boot中正確使用JPA

發(fā)布時間:2021-12-04 13:51:07 來源:億速云 閱讀:150 作者:小新 欄目:開發(fā)技術

這篇文章將為大家詳細講解有關怎么在Spring Boot中正確使用JPA,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。

一 JPA 基礎:常見操作

1.相關依賴

我們需要下面這些依賴支持我們完成這部分內容的學習:

<dependencies>         <dependency>             <groupId>org.springframework.boot</groupId>             <artifactId>spring-boot-starter-web</artifactId>         </dependency>         <dependency>             <groupId>org.springframework.boot</groupId>             <artifactId>spring-boot-starter-data-jpa</artifactId>         </dependency>         <dependency>             <groupId>mysql</groupId>             <artifactId>mysql-connector-java</artifactId>             <scope>runtime</scope>         </dependency>         <dependency>             <groupId>org.projectlombok</groupId>             <artifactId>lombok</artifactId>             <optional>true</optional>         </dependency>         <dependency>             <groupId>org.springframework.boot</groupId>             <artifactId>spring-boot-starter-test</artifactId>             <scope>test</scope>         </dependency>     </dependencies>

2.配置數據庫連接信息和JPA配置

下面的配置中需要單獨說一下 spring.jpa.hibernate.ddl-auto=create這個配置選項。

這個屬性常用的選項有四種:

  1. 鴻蒙官方戰(zhàn)略合作共建——HarmonyOS技術社區(qū)

  2. create:每次重新啟動項目都會重新創(chuàng)新表結構,會導致數據丟失

  3. create-drop:每次啟動項目創(chuàng)建表結構,關閉項目刪除表結構

  4. update:每次啟動項目會更新表結構

  5. validate:驗證表結構,不對數據庫進行任何更改

但是,一定要不要在生產環(huán)境使用 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 # 創(chuàng)建的表的 ENGINE 為 InnoDB spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL55Dialect

3.實體類

我們?yōu)檫@個類添加了 @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 步?很簡單,運行項目,查看數據如果發(fā)現(xiàn)控制臺打印出創(chuàng)建表的 sql  語句,并且數據庫中表真的被創(chuàng)建出來的話,說明你成功完成前面 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.創(chuàng)建操作數據庫的 Repository 接口

@Repository public interface PersonRepository extends JpaRepository<Person, Long> { }

首先這個接口加了 @Repository 注解,代表它和數據庫操作有關。另外,它繼承了  JpaRepository接口,而JpaRepository長這樣:

@NoRepositoryBean 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); }

這表明我們只要繼承了JpaRepository 就具有了 JPA 為我們提供好的增刪改查、分頁查詢以及根據條件查詢等方法。

4.1 JPA 自帶方法實戰(zhàn)

1) 增刪改查

1.保存用戶到數據庫

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

save()方法對應 sql 語句就是:insert into person (age, name) values  (23,"snailclimb")

2.根據 id 查找用戶

Optional<Person> 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()方法來實現(xiàn),比如:

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<Person> findByName(String name);

如果你想要找到年齡大于某個值的人,你可以這樣:

List<Person> findByAgeGreaterThan(int age);

4.2 自定義 SQL 語句實戰(zhàn)

很多時候我們自定義 sql 語句會非常有用。

根據 name 來查找 Person:

@Query("select p from Person p where p.name = :name")     Optional<Person> 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 創(chuàng)建異步方法

如果我們需要創(chuàng)建異步方法的話,也比較方便。

異步方法在調用時立即返回,然后會被提交給TaskExecutor執(zhí)行。當然你也可以選擇得出結果后才返回給客戶端。如果對 Spring Boot  異步編程感興趣的話可以看這篇文章:《新手也能看懂的 SpringBoot 異步編程指南》 。

@Async Future<User> findByName(String name);  @Async CompletableFuture<User> 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<Person> personOptional = personRepository.findById(id);         assertTrue(personOptional.isPresent());         assertEquals("SnailClimb", personOptional.get().getName());         assertEquals(Integer.valueOf(23), personOptional.get().getAge());          List<Person> personList = personRepository.findByAgeGreaterThan(18);         assertEquals(1, personList.size());         // 清空數據庫         personRepository.deleteAll();     }      /**      * 自定義 query sql 查詢語句查找 person      */      @Test     public void should_get_person_use_custom_query() {         // 查找所有字段         Optional<Person> 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<Person> 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 語句進行查詢或者更新數據庫。

創(chuàng)建異步的方法。

在下一篇關于 JPA 的文章中我會介紹到非常重要的兩個知識點:

基本分頁功能實現(xiàn)

多表聯(lián)合查詢以及多表聯(lián)合查詢下的分頁功能實現(xiàn)。

二 JPA 連表查詢和分頁

對于連表查詢,在 JPA 中還是非常常見的,由于 JPA 可以在 respository 層自定義 SQL 語句,所以通過自定義 SQL  語句的方式實現(xiàn)連表還是挺簡單。這篇文章是在上一篇入門 JPA的文章的基礎上寫的,不了解 JPA 的可以先看上一篇文章。

在上一節(jié)的基礎上我們新建了兩個實體類,如下:

1.相關實體類創(chuàng)建

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語句實現(xiàn)連表查詢

假如我們當前要通過 person 表的 id 來查詢 Person 的話,我們知道 Person  的信息一共分布在Company、School、Person這三張表中,所以,我們如果要把 Person 的信息都查詢出來的話是需要進行連表查詢的。

首先我們需要創(chuàng)建一個包含我們需要的 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<UserDTO> getUserInformation(@Param("personId") Long personId);

可以看出上面的 sql 語句和我們平時寫的沒啥區(qū)別,差別比較大的就是里面有一個 new 對象的操作。

3.自定義 SQL 語句連表查詢并實現(xiàn)分頁操作

假如我們要查詢當前所有的人員信息并實現(xiàn)分頁的話,你可以按照下面這種方式來做??梢钥吹?,為了實現(xiàn)分頁,我們在@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<UserDTO> getUserInformationList(Pageable pageable);

實際使用:

//分頁選項 PageRequest pageRequest = PageRequest.of(0, 3, Sort.Direction.DESC, "age"); Page<UserDTO> 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  中也非常簡單。比如下面的方法就實現(xiàn)了,根據名字過濾需要的人員信息。

@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<UserDTO> filterUserInfo(List peopleList);

實際使用:

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

4.2 BETWEEN 查詢

查詢滿足某個范圍的值。比如下面的方法就實現(xiàn)查詢滿足某個年齡范圍的人員的信息。

@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<UserDTO> 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<Person> personList = personRepository.findByAgeGreaterThan(18);         assertEquals(1, personList.size());     }      @Sql(scripts = {"classpath:/init.sql"})     @Test     public void should_get_user_info() {         Optional<UserDTO> 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<UserDTO> 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<String> personList=new ArrayList<>(Arrays.asList("person1","person2"));         List<UserDTO> userDTOS = personRepository.filterUserInfo(personList);         System.out.println(userDTOS);     }      @Sql(scripts = {"classpath:/init.sql"})     @Test     public void should_filter_user_info_by_age() {         List<UserDTO> userDTOS = personRepository.filterUserInfoByAge(19,20);         System.out.println(userDTOS);     } }

關于“怎么在Spring Boot中正確使用JPA”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,使各位可以學到更多知識,如果覺得文章不錯,請把它分享出去讓更多的人看到。

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI