芋道 Spring Boot JPA 入門(一)之快速入門

  • 2019 年 11 月 29 日
  • 筆記

摘要: 原創出處 http://www.iocoder.cn/Spring-Boot/JPA/ 「芋道源碼」歡迎轉載,保留摘要,謝謝!

  • 1. 概述
  • 2. 快速入門
  • 3. 分頁操作
  • 4. 基於方法名查詢
  • 5. 基於註解查詢
  • 666. 彩蛋

本文,我們基於 Spring Boot 2.X 版本。

1. 概述

我們,咱們來學習下 Spring Data JPA 。

相信不少胖友之前有了解過 JPA、Hibernate ,那麼 JPA、Hibernate、Spring Data JPA 這三者是什麼關係呢?我們來一起理一理。

JPA ,全稱 Java Persistence API ,是由 Java 定義的 Java ORM 以及實體操作 API 的標準。正如最早學習 JDBC 規範,Java 自身並未提供相關的實現,而是 MySQL 提供 MySQL mysql-connector-java 驅動,Oracle 提供 oracle-jdbc 驅動。而實現 JPA 規範的有:

  • Hibernate ORM
  • Oracle TopLink
  • Apache OpenJPA

Spring Data JPA ,是 Spring Data 提供的一套簡化的 JPA 開發的框架。

  • 內置 CRUD、分頁、排序等功能的操作。
  • 根據約定好的方法名規則,自動生成對應的查詢操作。
  • 使用 @Query 註解,自定義 SQL 。

所以,絕大多數情況下,我們無需編寫程式碼,直接調用 JPA 的 API 。也因此,在我們使用的 Spring Data JPA 的項目中,如果想要替換底層使用的 JPA 實現框架,在未使用到相關 JPA 實現框架的特殊特性的情況下,可以透明替換。

關於這一點,我們在 《芋道 Spring Boot Redis 入門》 中,已經看到 Spring Data Redis 也是已經看到這樣的好處。

總的來說,就是如下一張圖:

FROM 《spring data jpa hibernate jpa 三者之間的關係》

當然,絕大多數情況下,我們使用的 JPA 實現框架是 Hibernate ORM 。所以整個調用過程是:

應用程式 => Repository => Spring Data JPA => Hibernate  

2. 快速入門

示例程式碼對應倉庫:lab-13-jpa 。

本小節,我們會使用 spring-boot-starter-data-jpa 自動化配置 Spring Data JPA 。同時,演示 Spring Data JPA 的 CRUD 的操作。

2.1 引入依賴

pom.xml 文件中,引入相關依賴。

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">      <parent>          <groupId>org.springframework.boot</groupId>          <artifactId>spring-boot-starter-parent</artifactId>          <version>2.1.3.RELEASE</version>          <relativePath/> <!-- lookup parent from repository -->      </parent>      <modelVersion>4.0.0</modelVersion>        <artifactId>lab-13-jpa</artifactId>        <dependencies>          <!-- 實現對資料庫連接池的自動化配置 -->          <!-- 實際上 spring-boot-starter-data-jpa 已經包括 spring-boot-starter-jdbc -->          <dependency>              <groupId>org.springframework.boot</groupId>              <artifactId>spring-boot-starter-jdbc</artifactId>          </dependency>          <dependency> <!-- 本示例,我們使用 MySQL -->              <groupId>mysql</groupId>              <artifactId>mysql-connector-java</artifactId>              <version>5.1.48</version>          </dependency>            <!-- 實現對 Spring Data JPA 的自動化配置 -->          <dependency>              <groupId>org.springframework.boot</groupId>              <artifactId>spring-boot-starter-data-jpa</artifactId>          </dependency>            <!-- 方便等會寫單元測試 -->          <dependency>              <groupId>org.springframework.boot</groupId>              <artifactId>spring-boot-starter-test</artifactId>              <scope>test</scope>          </dependency>      </dependencies>    </project>  

具體每個依賴的作用,胖友自己認真看下艿艿添加的所有注釋噢。

另外,在 spring-boot-starter-data-jpa 中,已經默認引入了 Hibernate 的依賴。

2.2 Application

創建 Application.java 類,配置 @SpringBootApplication 註解即可。程式碼如下:

// Application.java    @SpringBootApplication  public class Application {  }  

2.3 配置文件

application.yml 中,添加 JPA 配置,如下:

spring:    # datasource 數據源配置內容    datasource:      url: jdbc:mysql://47.112.193.81:3306/testb5f4?useSSL=false&useUnicode=true&characterEncoding=UTF-8      driver-class-name: com.mysql.jdbc.Driver      username: testb5f4      password: F4df4db0ed86@11    # JPA 配置內容,對應 JpaProperties 類    jpa:      show-sql: true # 列印 SQL 。生產環境,建議關閉      # Hibernate 配置內容,對應 HibernateProperties 類      hibernate:        ddl-auto: none  
  • datasource 配置項,配置 datasource 數據源配置內容。
  • jpa 配置項,配置 Spring Data JPA 配置內容,對應 `org.springframework.boot.autoconfigure.orm.jpa.JpaProperties.java` 類。
  • hibernate 配置項,配置 Hibernate 配置內容,對應 org.springframework.boot.autoconfigure.orm.jpa.HibernateProperties.java 類。
    • create :每次載入 hibernate 時都會刪除上一次的生成的表,然後根據你的 model 類再重新來生成新表,哪怕兩次沒有任何改變也要這樣執行,這就是導致資料庫表數據丟失的一個重要原因。
    • create-drop :每次載入 hibernate 時根據 model 類生成表,但是 sessionFactory 一關閉,表就自動刪除。
    • update :最常用的屬性,第一次載入 hibernate 時根據 model 類會自動建立起表的結構(前提是先建立好資料庫),以後載入 hibernate 時根據 model 類自動更新表結構,即使表結構改變了但表中的行仍然存在不會刪除以前的行。要注意的是當部署到伺服器後,表結構是不會被馬上建立起來的,是要等應用第一次運行起來後才會。
    • validate :每次載入 hibernate 時,驗證創建資料庫表結構,只會和資料庫中的表進行比較,不會創建新表,但是會插入新值。
    • 建議,生產環境下,建議配置 none ,不使用 Hibernate Auto DDL 功能。? 啟動個項目,就自動變更資料庫表結構,多危險啊~
    • 實際項目無需配置 hibernate 配置項,這裡僅僅是演示,讓胖友知道這回事。
    • ddl-auto 配置項,設置 Hibernate DDL 處理策略。一共有 nonecreatecreate-dropupdatevalidate 五個選項。 FROM 《jpa 的 hibernate.ddl-auto 的幾個屬性值區別》

2.4 UserDO

cn.iocoder.springboot.lab13.jpa.dataobject 包路徑下,創建 UserDO.java 類,用戶 DO 。程式碼如下:

// UserDO.java    @Entity  @Table(name = "users")  public class UserDO {        /**       * 用戶編號       */      @Id      @GeneratedValue(strategy = GenerationType.IDENTITY,  // strategy 設置使用資料庫主鍵自增策略;              generator = "JDBC") // generator 設置插入完成後,查詢最後生成的 ID 填充到該屬性中。      private Integer id;      /**       * 帳號       */      @Column(nullable = false)      private String username;      /**       * 密碼(明文)       *       * ps:生產環境下,千萬不要明文噢       */      @Column(nullable = false)      private String password;      /**       * 創建時間       */      @Column(name = "create_time", nullable = false)      private Date createTime;        // ... 省略 setting/getting 方法    }  

關於 JPA 的註解的詳細說明,胖友後面再看看 《Spring Data JPA 中常用的註解詳解》 文章。我們,繼續往下看。

對應的創建表的 SQL 如下:

CREATE TABLE `users` (    `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '用戶編號',    `username` varchar(64) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '帳號',    `password` varchar(32) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '密碼',    `create_time` datetime DEFAULT NULL COMMENT '創建時間',    PRIMARY KEY (`id`),    UNIQUE KEY `idx_username` (`username`)  ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;  

2.5 UserRepository01

cn.iocoder.springboot.lab13.mybatis.repository 包路徑下,創建 UserRepository01 介面。程式碼如下:

// UserRepository01.java    public interface UserRepository01 extends CrudRepository<UserDO, Integer> {    }  
  • 繼承 org.springframework.data.repository.CrudRepository 介面,第一個泛型設置對應的實體是 UserDO ,第二個泛型設置對應的主鍵類型是 Integer 。
  • 因為實現了 CrudRepository 介面,Spring Data JPA 會自動生成對應的 CRUD 的程式碼。具體 CrudRepository 提供了哪些操作,胖友點擊 `CrudRepository.java` 查看。

2.6 簡單測試

創建 UserRepository01Test 測試類,我們來測試一下簡單的 UserRepository01 的每個操作。程式碼如下:

// UserRepository01.java    @RunWith(SpringRunner.class)  @SpringBootTest(classes = Application.class)  public class UserMapperTest {        @Autowired      private UserMapper userMapper;        @Test      public void testInsert() {          UserDO user = new UserDO().setUsername(UUID.randomUUID().toString())                  .setPassword("nicai").setCreateTime(new Date());          userMapper.insert(user);      }        @Test      public void testUpdateById() {          UserDO updateUser = new UserDO().setId(1)                  .setPassword("wobucai");          userMapper.updateById(updateUser);      }        @Test      public void testDeleteById() {          userMapper.deleteById(2);      }        @Test      public void testSelectById() {          userMapper.selectById(1);      }        @Test      public void testSelectByUsername() {          userMapper.selectByUsername("yunai");      }        @Test      public void testSelectByIds() {          List<UserDO> users = userMapper.selectByIds(Arrays.asList(1, 3));          System.out.println("users:" + users.size());      }    }  

具體的,胖友可以自己跑跑,妥妥的。

3. 分頁操作

示例程式碼對應倉庫:lab-13-jpa 。

Spring Data 提供 org.springframework.data.repository.PagingAndSortingRepository 介面,繼承 CrudRepository 介面,在 CRUD 操作的基礎上,額外提供分頁和排序的操作。程式碼如下:

// PagingAndSortingRepository.java    public interface PagingAndSortingRepository<T, ID> extends CrudRepository<T, ID> {        Iterable<T> findAll(Sort sort); // 排序操作        Page<T> findAll(Pageable pageable); // 分頁操作    }  

3.1 UserRepository02

cn.iocoder.springboot.lab13.mybatis.repository 包路徑下,創建 UserRepository02 介面。程式碼如下:

// UserRepository02.java    public interface UserRepository02 extends PagingAndSortingRepository<UserDO, Integer> {    }  
  • 實現 PagingAndSortingRepository 介面,第一個泛型設置對應的實體是 UserDO ,第二個泛型設置對應的主鍵類型是 Integer 。

3.2 簡單測試

創建 UserRepository02Test 測試類,我們來測試一下簡單的 UserRepository02 的每個操作。程式碼如下:

// UserRepository02Test.java    @RunWith(SpringRunner.class)  @SpringBootTest  public class UserRepository02Test {        @Autowired      private UserRepository02 userRepository;        @Test // 排序      public void testFindAll() {          // 創建排序條件          Sort sort = new Sort(Sort.Direction.DESC, "id");          // 執行排序操作          Iterable<UserDO> iterable = userRepository.findAll(sort);          // 列印          iterable.forEach(System.out::println);      }        @Test // 分頁      public void testFindPage() {          // 創建排序條件          Sort sort = new Sort(Sort.Direction.DESC, "id");          // 創建分頁條件          Pageable pageable = PageRequest.of(1, 10, sort);          // 執行分頁操作          Page<UserDO> page = userRepository.findAll(pageable);          // 列印          System.out.println(page.getTotalElements());          System.out.println(page.getTotalPages());      }    }  

具體的,胖友可以自己跑跑,妥妥的。