Spring Boot 2和JPA入門

banq發表於2019-01-16

在本教程中,我們將構建一個簡單的Spring Boot 2應用程式,可以使用JPA訪問Postgres資料庫。

背景: 
在我們開始之前,讓我們先了解一些定義。
 
什麼是JPA?
JPA代表“Java Persistence API”。它是一個java規範,定義瞭如何在Java平臺上管理關聯式資料庫中的資料。
 
什麼是Hibernate?
Hibernate ORM,通常簡稱為“Hibernate”,是JPA規範的一種實現。雖然直接使用Hibernate API很常見,但現在建議使用JPA介面,Hibernate作為底層框架。人們可以將JPA視為汽車中的控制元件,將Hibernate視為引擎。
 
什麼是Spring Data?
Spring資料是Spring提供的一組技術,它們提供抽象和實用程式框架,旨在促進資料訪問配置並減少樣板程式碼。更多資訊可以在這裡找到   。

設定Spring-boot應用程式:
在我們的示例中,我們將使用JPA / Postgres堆疊設定Spring-boot應用程式。為了開始,讓我們新增所需的依賴項。請注意,Spring-boot-starter-parent已被用作父專案。

<dependencies>
        
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>

        <dependency>
            <groupId>org.postgresql</groupId>
            <artifactId>postgresql</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-logging</artifactId>
        </dependency>
        
    </dependencies>


注意列表中的前兩個依賴項。第一個是“spring-boot-starter-data-jpa”。新增此依賴項將自動引入Java永續性庫,Hibernate-core,Spring-data和spring-boot-starter-jdbc。第二個依賴“postgresql”將新增所需的Postgres驅動程式,並且需要能夠與底層的Postgres資料庫管理系統進行互動。如果您正在使用其他DBMS,則需要為相應的驅動程式新增依賴項。

下一步是配置Spring啟動應用程式以訪問Postgres資料庫管理系統。為此,我們將設定必須將jdbc url,使用者名稱,密碼和hibernate.dll-auto屬性(稍後將詳細介紹)新增到application.properties檔案中。同樣,JDBC URL依賴於所使用的DBMS。我們的資料庫伺服器上未配置密碼,因此將其留空(不要在prod環境中執行此操作)。

spring.datasource.url=jdbc:postgresql://localhost/nullbeansdemo
spring.datasource.username=postgres
spring.datasource.password=
spring.jpa.hibernate.ddl-auto=create


DDL代表“資料定義語言”。它是一種用於定義資料庫結構和模式的程式語言。spring.jpa.hibernate.ddl-auto的值可以設定屬性以指示Hibernate建立我們的資料庫模式,更新它,驗證它,或者什麼都不做。在我們的示例中,我們將值設定為“create”。這意味著在應用程式啟動時,Hibernate將檢查我們建立的資料模型,並嘗試建立與這些模型匹配的資料庫模式。這樣做的好處是您不需要主要的不同資料庫建立指令碼集。如果您的應用程式部署在具有不同資料庫系統供應商的不同平臺上,則效益更高,因為您不需要為不同的供應商系統建立指令碼。當然,可以透過將值設定為“none”來關閉此功能。在這種情況下,您需要確保資料庫模式與所需的資料庫表一起存在。 這裡

建立我們的第一個實體:
現在我們已經完成了應用程式配置,現在是時候建立我們的第一個永續性實體了。在我們的示例中,我們將建立一個“銀行帳戶”實體。我們將在後面的文章中擴充套件該示例。目前,我們的銀行賬戶實體將如下所示:

package com.nullbeans.persistence.models;

import javax.persistence.*;

@Entity
public class BankAccount {

    private long id;

    private int version;

    private String accountNumber;

    private boolean isActive;

    public BankAccount() {
    }

    @Id
    @GeneratedValue(strategy= GenerationType.AUTO)
    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    @Version
    public int getVersion() {
        return version;
    }

    public void setVersion(int version) {
        this.version = version;
    }

    public String getAccountNumber() {
        return accountNumber;
    }

    public void setAccountNumber(String accountNumber) {
        this.accountNumber = accountNumber;
    }

    public boolean isActive() {
        return isActive;
    }

    public void setActive(boolean active) {
        isActive = active;
    }

    @Override
    public String toString() {
        return "BankAccount{" +
                "id=" + id +
                ", version=" + version +
                ", accountNumber='" + accountNumber + '\'' +
                ", isActive=" + isActive +
                '}';
    }
}


我們來看看這個類中使用的一些註釋:
 
@Entity: 使用@Entity註釋的類被視為永續性實體定義。通常這意味著類對映到資料庫表。由於Hibernate使用此批註掃描類的模型包,因此需要此批註。
@Id:  指定帶註釋的變數將被視為實體的主鍵。
@GeneratedValue:此批註指示給定值是生成的值。換句話說,使用者不應該明確設定此值。它將自動生成。生成主鍵有多種策略,例如使用序列中的值,使用基礎表或讓資料庫決定如何建立值。為簡單起見,我們使用“AUTO”,這意味著Hibernate將決定如何生成金鑰。
@Version:  版本註釋表示給定實體的版本號。每次修改實體的例項時,該例項的版本都會遞增。版本號從0開始。

設定儲存庫:
需要編寫和實現DAO的日子已經一去不復返了,一次只有一個介面,類和方法,以便有辦法訪問和管理特定實體的資料。透過Spring-Data CrudRepository介面,資料訪問物件的實現得到了極大的簡化。所需要的只是建立一個實現“CrudRepository”介面的介面,您就完成了。

package com.nullbeans.persistence.repositories;

import com.nullbeans.persistence.models.BankAccount;
import org.springframework.data.repository.CrudRepository;

import java.util.List;

public interface BankAccountRepository extends CrudRepository<BankAccount, Long> {

    List<BankAccount> findByAccountNumber(String accountNumber);

}

BankAccountRepository只需要擴充套件CrudRepository介面,使用BankAccount類和Long(主鍵類)作為型別化引數。預設情況下,CrudRepository介面提供了方便的方法,如  save,saveAll,findById,findall,delete,deleteAll等。 如果我們需要額外的功能,例如透過銀行帳號進行搜尋,該怎麼辦?在這種情況下,我們只需要建立一個名為“findByAccountNumber”的方法。由於我們使用與實體類中定義的相同的變數名,因此Spring資料可以自動計算出搜尋引數和搜尋查詢。

測試
讓我們透過嘗試實體和我們剛剛建立的相應儲存庫將所有內容放在一起。為此,我們將建立一個“CommandLineRunner”bean。一旦我們啟動Spring-boot應用程式,這個bean就會執行,當需要啟動整個應用程式上下文並針對特定過程進行測試時,它是一個有用的開發功能。我們將從應用程式上下文中獲取銀行儲存庫,並嘗試執行一些儲存/搜尋操作。

package com.nullbeans;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.nullbeans.persistence.models.BankAccount;
import com.nullbeans.persistence.repositories.BankAccountRepository;
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 NullbeansPersistenceApplication {

    private static final Logger log = LoggerFactory.getLogger(NullbeansPersistenceApplication.class);

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


    @Bean
    public CommandLineRunner example1(BankAccountRepository bankAccountRepository){

        return new CommandLineRunner() {
            @Override
            public void run(String... args) throws Exception {
                BankAccount bankAccount = new BankAccount();
                bankAccount.setAccountNumber("SAVINGS100");
                bankAccount.setActive(true);
                bankAccountRepository.save(bankAccount);

                BankAccount bankAccount1 = new BankAccount();
                bankAccount1.setAccountNumber("CREDIT101");
                bankAccount1.setActive(true);
                bankAccountRepository.save(bankAccount1);

                log.info("Saved the bank accounts successfully\r\n");

                log.info("Quering DB for bank accounts");
                for(BankAccount persistentAccount: bankAccountRepository.findAll()){
                    log.info("Found account: {}\r\n", persistentAccount);
                }

                log.info("Searching by bank account number");
                BankAccount searchResult = bankAccountRepository.findByAccountNumber("SAVINGS100").get(0);
                log.info("Found bank account: {}", searchResult);


            }
        };

    }
}


在我們的示例中,我們建立了兩個銀行帳戶。使用儲存庫的save方法儲存每個銀行帳戶。然後,我們將使用find all方法使用findall方法獲取資料庫中的所有帳戶。最後一步是使用我們的其他搜尋方法,使用帳號搜尋銀行帳戶。如果我們執行程式,我們將得到以下輸出:

2019-01-14 21:51:49.975  INFO 10292 --- [           main] j.LocalContainerEntityManagerFactoryBean : 
Initialized JPA EntityManagerFactory for persistence unit 'default'
2019-01-14 21:51:50.658  INFO 10292 --- [           main] c.n.NullbeansPersistenceApplication      : 
Started NullbeansPersistenceApplication in 5.523 seconds (JVM running for 6.361)
2019-01-14 21:51:50.751  INFO 10292 --- [           main] c.n.NullbeansPersistenceApplication      : 
Saved the bank accounts successfully
2019-01-14 21:51:50.751  INFO 10292 --- [           main] c.n.NullbeansPersistenceApplication      : 
Quering DB for bank accounts
2019-01-14 21:51:50.775  INFO 10292 --- [           main] o.h.h.i.QueryTranslatorFactoryInitiator  : 
HHH000397: Using ASTQueryTranslatorFactory
2019-01-14 21:51:50.927  INFO 10292 --- [           main] c.n.NullbeansPersistenceApplication      : 
Found account: BankAccount{id=1, version=0, accountNumber='SAVINGS100', isActive=true}
2019-01-14 21:51:50.928  INFO 10292 --- [           main] c.n.NullbeansPersistenceApplication      : 
Found account: BankAccount{id=2, version=0, accountNumber='CREDIT101', isActive=true}
2019-01-14 21:51:50.928  INFO 10292 --- [           main] c.n.NullbeansPersistenceApplication      : 
Searching by bank account number
2019-01-14 21:51:50.977  INFO 10292 --- [           main] c.n.NullbeansPersistenceApplication      : 
Found bank account: BankAccount{id=1, version=0, accountNumber='SAVINGS100', isActive=true}
2019-01-14 21:51:50.981  INFO 10292 --- [       Thread-3] j.LocalContainerEntityManagerFactoryBean : 
Closing JPA EntityManagerFactory for persistence unit 'default'
2019-01-14 21:51:50.984  INFO 10292 --- [       Thread-3] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown initiated...
2019-01-14 21:51:50.988  INFO 10292 --- [       Thread-3] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown completed.


如您所見,儲存庫能夠成功使用帳號找到銀行帳戶。findall方法也能夠在儲存之後找到我們所有的實體。請注意,如果您的應用程式有多個帶有JPA註釋實體的軟體包,那麼Spring引導將自動掃描它們。如果您只想掃描特定的包,則可以使用  @EntityScan 註釋。

EntityScan({"com.nullbeans.persistence.models"})
@SpringBootApplication
public class NullbeansPersistenceApplication {


現在,讓我們快速瀏覽資料庫方面。我們將看到Hibernate已經自動建立了我們的模式,並且我們的資料已經保留。

總結
在本教程中,我們探討了如何使用JPA後端啟動並執行Spring啟動應用程式。我們在POM.xml中新增了所需的Spring JPA依賴項和所需的DBMS驅動程式。然後我們將所需的配置新增到application.properties檔案中。我們使用JPA註釋定義了永續性實體,並建立了一個用於訪問該實體資料的Repository。最後,我們能夠使用CommandLineRunner bean測試應用程式,並且我們能夠確認應用程式是否按預期執行。點選標題見原文

相關文章