使用 JPA 訪問資料

本指南將引導您構建一個應用程式,該應用程式使用 Spring Data JPA 在關係資料庫中儲存和檢索資料。

您將構建什麼

您將構建一個將 Customer 物件儲存在記憶體資料庫中的應用程式。

您需要什麼

如何完成本指南

與大多數 Spring 入門指南一樣,您可以從頭開始並完成每個步驟,也可以跳過您已熟悉的基本設定步驟。無論哪種方式,您最終都會得到可工作的程式碼。

從頭開始,請轉到從 Spring Initializr 開始

跳過基礎知識,請執行以下操作

完成後,您可以將您的結果與 gs-accessing-data-jpa/complete 中的程式碼進行比較。

從 Spring Initializr 開始

您可以使用此預初始化專案並單擊“生成”以下載 ZIP 檔案。此專案已配置為符合本教程中的示例。

手動初始化專案

  1. 導航到 https://start.spring.io。此服務會為您拉取應用程式所需的所有依賴項,併為您完成大部分設定。

  2. 選擇 Gradle 或 Maven 以及您想要使用的語言。

  3. 單擊依賴項並選擇Spring Data JPA,然後選擇H2 Database

  4. 單擊生成

  5. 下載生成的 ZIP 檔案,這是一個已根據您的選擇配置好的 Web 應用程式存檔。

如果您的 IDE 集成了 Spring Initializr,您可以從 IDE 中完成此過程。
您還可以從 GitHub fork 專案,並在您的 IDE 或其他編輯器中開啟它。

定義一個簡單的實體

在此示例中,您儲存 Customer 物件,每個物件都標註為 JPA 實體。以下列表顯示了 Customer 類

Java
package com.example.accessingdatajpa;

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;

@Entity
public class Customer {

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private Long id;
    private String firstName;
    private String lastName;

    protected Customer() {}

    public Customer(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }

    @Override
    public String toString() {
        return String.format(
                "Customer[id=%d, firstName='%s', lastName='%s']",
                id, firstName, lastName);
    }

    public Long getId() {
        return id;
    }

    public String getFirstName() {
        return firstName;
    }

    public String getLastName() {
        return lastName;
    }
}
Kotlin
package com.example.accessingdatajpa

import jakarta.persistence.Entity
import jakarta.persistence.GeneratedValue
import jakarta.persistence.GenerationType
import jakarta.persistence.Id

@Entity
class Customer(
    var firstName: String = "",
    var lastName: String = ""
) {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    var id: Long? = null

    override fun toString(): String =
        "Customer[id=$id, firstName='$firstName', lastName='$lastName']"
}

這裡有一個 Customer 類,它有三個屬性:idfirstNamelastName。您還有兩個建構函式。預設建構函式僅為 JPA 而存在。您不直接使用它,因此它被指定為 protected。另一個建構函式是您用於建立要儲存到資料庫的 Customer 例項的建構函式。

Customer 類用 @Entity 註解,表示它是一個 JPA 實體。(由於不存在 @Table 註解,因此假定此實體對映到名為 Customer 的表。)

Customer 物件的 id 屬性用 @Id 註解,以便 JPA 將其識別為物件的 ID。id 屬性還用 @GeneratedValue 註解,表示 ID 應該自動生成。

其他兩個屬性 firstNamelastName 未註解。假定它們對映到與屬性本身同名的列。

方便的 toString() 方法會打印出客戶的屬性。

建立簡單查詢

Spring Data JPA 專注於使用 JPA 將資料儲存在關係資料庫中。它最引人注目的功能是能夠在執行時從儲存庫介面自動建立儲存庫實現。

要了解其工作原理,請建立一個與 Customer 實體一起工作的儲存庫介面,如以下列表所示

Java
package com.example.accessingdatajpa;

import java.util.List;

import org.springframework.data.repository.CrudRepository;

public interface CustomerRepository extends CrudRepository<Customer, Long> {

    List<Customer> findByLastName(String lastName);

    Customer findById(long id);
}
Kotlin
package com.example.accessingdatajpa

import org.springframework.data.repository.CrudRepository

interface CustomerRepository : CrudRepository<Customer, Long> {
    fun findByLastName(lastName: String): List<Customer>
}

CustomerRepository 擴充套件了 CrudRepository 介面。它處理的實體型別和 ID,即 CustomerLong,在 CrudRepository 上的泛型引數中指定。透過擴充套件 CrudRepositoryCustomerRepository 繼承了幾個用於處理 Customer 持久化的方法,包括用於儲存、刪除和查詢 Customer 實體的方法。

Spring Data JPA 還允許您透過宣告方法簽名來定義其他查詢方法。例如,CustomerRepository 包含 findByLastName() 方法。

在典型的 Java 應用程式中,您可能會期望編寫一個實現 CustomerRepository 的類。然而,這正是 Spring Data JPA 如此強大的原因:您無需編寫儲存庫介面的實現。Spring Data JPA 會在您執行應用程式時建立實現。

現在您可以連線此示例並檢視其外觀!

建立應用程式類

Spring Initializr 為應用程式建立了一個簡單的類。以下列表顯示了 Initializr 為此示例建立的類

Java
package com.example.accessingdatajpa;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class AccessingDataJpaApplication {

    public static void main(String[] args) {
        SpringApplication.run(AccessingDataJpaApplication.class, args);
    }

}
Kotlin
package com.example.accessingdatajpa

import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication

@SpringBootApplication
class AccessingDataJpaApplication

fun main(args: Array<String>) {
    runApplication<AccessingDataJpaApplication>(*args)
}

@SpringBootApplication 是一個方便的註解,它添加了以下所有內容

  • @Configuration:將類標記為應用程式上下文的 bean 定義源。

  • @EnableAutoConfiguration:告訴 Spring Boot 根據類路徑設定、其他 bean 和各種屬性設定開始新增 bean。例如,如果 spring-webmvc 在類路徑中,此註解會將應用程式標記為 Web 應用程式並激活關鍵行為,例如設定 DispatcherServlet

  • @ComponentScan:告訴 Spring 在 com/example 包中查詢其他元件、配置和服務,使其能夠找到控制器。

main() 方法使用 Spring Boot 的 SpringApplication.run() 方法啟動應用程式。您是否注意到沒有一行 XML?也沒有 web.xml 檔案。這個 Web 應用程式是 100% 純 Java,您不必處理任何管道或基礎設施的配置。

現在您需要修改 Initializr 為您建立的簡單類。要獲取輸出(在此示例中,輸出到控制檯),您需要設定一個日誌記錄器。然後,您需要設定一些資料並使用它來生成輸出。以下列表顯示了完成的 AccessingDataJpaApplication

Java
package com.example.accessingdatajpa;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
public class AccessingDataJpaApplication {

    private static final Logger logger = LoggerFactory.getLogger(AccessingDataJpaApplication.class);

    public static void main(String[] args) {
        SpringApplication.run(AccessingDataJpaApplication.class);
    }

    @Bean
    public CommandLineRunner demo(CustomerRepository repository) {
        return (args) -> {
            // save a few customers
            repository.save(new Customer("Jack", "Bauer"));
            repository.save(new Customer("Chloe", "O'Brian"));
            repository.save(new Customer("Kim", "Bauer"));
            repository.save(new Customer("David", "Palmer"));
            repository.save(new Customer("Michelle", "Dessler"));

            // fetch all customers
            logger.info("Customers found with findAll():");
            logger.info("-------------------------------");
            repository.findAll().forEach(customer -> {
                logger.info(customer.toString());
            });
            logger.info("");

            // fetch an individual customer by ID
            Customer customer = repository.findById(1L);
            logger.info("Customer found with findById(1L):");
            logger.info("--------------------------------");
            logger.info(customer.toString());
            logger.info("");

            // fetch customers by last name
            logger.info("Customer found with findByLastName('Bauer'):");
            logger.info("--------------------------------------------");
            repository.findByLastName("Bauer").forEach(bauer -> {
                logger.info(bauer.toString());
            });
            logger.info("");
        };
    }

}
Kotlin
package com.example.accessingdatajpa

import org.slf4j.LoggerFactory
import org.springframework.boot.CommandLineRunner
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
import org.springframework.context.annotation.Bean

private val logger = LoggerFactory.getLogger(AccessingDataJpaApplication::class.java)

@SpringBootApplication
class AccessingDataJpaApplication {

    @Bean
    fun demo(repository: CustomerRepository) = CommandLineRunner {
        // save a few customers
        repository.saveAll(
            listOf(
                Customer("Jack", "Bauer"),
                Customer("Chloe", "O'Brian"),
                Customer("Kim", "Bauer"),
                Customer("David", "Palmer"),
                Customer("Michelle", "Dessler")
            )
        )

        // fetch all customers
        logger.info("Customers found with findAll():")
        logger.info("-------------------------------")
        repository.findAll().forEach { customer ->
            logger.info(customer.toString())
        }
        logger.info("")

        // fetch an individual customer by ID
        val customer = repository.findById(1L).orElseThrow()
        logger.info("Customer found with findById(1L):")
        logger.info("--------------------------------")
        logger.info(customer.toString())
        logger.info("")

        // fetch customers by last name
        logger.info("Customer found with findByLastName('Bauer'):")
        logger.info("--------------------------------------------")
        repository.findByLastName("Bauer").forEach { bauer ->
            logger.info(bauer.toString())
        }
        logger.info("")
    }
}

fun main(args: Array<String>) {
    runApplication<AccessingDataJpaApplication>(*args)
}

AccessingDataJpaApplication 類包含一個 demo() 方法,該方法對 CustomerRepository 進行了一些測試。首先,它從 Spring 應用程式上下文中獲取 CustomerRepository。然後它儲存一些 Customer 物件,演示了 save() 方法並設定了一些要處理的資料。接下來,它呼叫 findAll() 從資料庫中獲取所有 Customer 物件。然後它呼叫 findById() 透過 ID 獲取單個 Customer。最後,它呼叫 findByLastName() 查詢所有姓氏為“Bauer”的客戶。demo() 方法返回一個 CommandLineRunner bean,該 bean 在應用程式啟動時自動執行程式碼。

預設情況下,Spring Boot 啟用 JPA 儲存庫支援,並在 @SpringBootApplication 所在的包(及其子包)中查詢。如果您的配置中 JPA 儲存庫介面定義位於不可見的包中,您可以使用 @EnableJpaRepositories 及其型別安全的 basePackageClasses=MyRepository.class 引數指出備用包。

構建可執行 JAR

您可以使用 Gradle 或 Maven 從命令列執行應用程式。您還可以構建一個包含所有必要依賴項、類和資源並執行的單個可執行 JAR 檔案。構建可執行 JAR 使在整個開發生命週期中,跨不同環境等,輕鬆交付、版本化和部署服務作為應用程式。

如果您使用 Gradle,您可以透過使用 ./gradlew bootRun 執行應用程式。或者,您可以透過使用 ./gradlew build 構建 JAR 檔案,然後按如下方式執行 JAR 檔案

java -jar build/libs/gs-accessing-data-jpa-0.1.0.jar

如果您使用 Maven,您可以透過使用 ./mvnw spring-boot:run 執行應用程式。或者,您可以使用 ./mvnw clean package 構建 JAR 檔案,然後按如下方式執行 JAR 檔案

java -jar target/gs-accessing-data-jpa-0.1.0.jar
這裡描述的步驟建立了一個可執行的 JAR。您還可以構建一個經典的 WAR 檔案

當您執行應用程式時,您應該看到類似於以下的輸出

== Customers found with findAll():
Customer[id=1, firstName='Jack', lastName='Bauer']
Customer[id=2, firstName='Chloe', lastName='O'Brian']
Customer[id=3, firstName='Kim', lastName='Bauer']
Customer[id=4, firstName='David', lastName='Palmer']
Customer[id=5, firstName='Michelle', lastName='Dessler']

== Customer found with findById(1L):
Customer[id=1, firstName='Jack', lastName='Bauer']

== Customer found with findByLastName('Bauer'):
Customer[id=1, firstName='Jack', lastName='Bauer']
Customer[id=3, firstName='Kim', lastName='Bauer']

總結

恭喜!您已經編寫了一個簡單的應用程式,該應用程式使用 Spring Data JPA 將物件儲存到資料庫並從資料庫中獲取物件,所有這些都無需編寫具體的儲存庫實現。

如果您希望輕鬆地透過基於超媒體的 RESTful 前端公開 JPA 儲存庫,您可能需要閱讀使用 REST 訪問 JPA 資料

另請參閱

以下指南也可能有所幫助

想寫新指南或為現有指南做貢獻嗎?請檢視我們的貢獻指南

所有指南的程式碼均採用 ASLv2 許可,文字內容採用署名-禁止演繹知識共享許可

獲取程式碼

免費

在雲端工作

在 Spring Academy 的雲端完成本指南。

前往 Spring Academy