spring data jpa hibernate

Spring Boot EP 10:透過Spring Data JPA與Hibernate讀取(select)資料庫

準備資料

請參考前一篇:Spring Boot EP 9:準備資料庫(MariaDB)及資料(市場指數及個股每日股價)

安裝Spring Data JPA 、Hibernate與MariaDB Client

在pom.xml加上以下兩個相依套件的設定,存檔後Reload專案,即完成。

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

<dependency>
	<groupId>org.mariadb.jdbc</groupId>
	<artifactId>mariadb-java-client</artifactId>
	<scope>runtime</scope>
</dependency>

從資料庫取得所有市場(Market)的清單

步驟1:在application.properties增加資料庫連接的設定,如下:

# 資料庫目標
spring.datasource.url=jdbc:mariadb://{ip or hostname}:3306/STOCK_MARKET
# 資料庫登入驗證的帳號
spring.datasource.username=${database.username}
# 資料庫登入密碼
spring.datasource.password=${database.password}
# 選定org.mariadb.jdbc.Driver作為連接資料庫的Driver
spring.datasource.driver-class-name=org.mariadb.jdbc.Driver
# Hibernate對資料表的操作,none表示不動作
spring.jpa.hibernate.ddl-auto=none

註:spring.jpa.hibernate.ddl-auto有5個狀態可以使用,分別為:

  • create:每次專案啟動都會將依照Model建置資料表,就算已經存在也會被覆蓋。
  • create-drop:每次專案啟動都會將依照Model建置資料表,專案結束後執行這些資料表會被刪除。
  • update:每次專案啟動都會將依照Model更新資料表異動的部分。
  • validate:自動比較Model與資料表的差異,不會更動資料表,但會將資料寫入(如果有定義初始化資料的話)。
  • none:什麼都不動作。

步驟2:在”STOCKMARKET/src/main/java/stockmarket/jovepater/com/stockmarket/”下建立一個名為Models的資料夾,並新增一個MarketModel.java,如下圖:

步驟3:依照資料表MARKETS的內容來設計MarketModel這個Model。

package stockmarket.jovepater.com.stockmarket.Models;

import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

// 定義這個類別為實體,同資料表的意思
@Entity
// 對應到資料庫中名為MARKETS的資料表
@Table(name = "MARKETS")
public class MarketModel {

    // 宣告這個類別的內容,依照MARKETS資料表的欄位設計
    // @Id表示這個資料表的Primary Key,這張表只有一個Primary Key,不需要另外處理
    @Id
    private String MARKET_CODE;
    private String MARKET_NAME;

    public MarketModel() {

    }

    public MarketModel(String MARKET_CODE, String MARKET_NAME) {
        this.MARKET_CODE = MARKET_CODE;
        this.MARKET_NAME = MARKET_NAME;
    }

    // getters and setters ...
}

步驟4:在S”TOCKMARKET/src/main/java/stockmarket/jovepater/com/stockmarket/”下建立一個名為Repositories的資料夾,並新增一個MarketRepository.java,如下圖:

步驟5:MarketRepository.java將實作兩個功能,讀取全部的市場清單及依照市場代碼讀取資料。

package stockmarket.jovepater.com.stockmarket.Repositories;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

import java.util.List;
import stockmarket.jovepater.com.stockmarket.Models.MarketModel;

@Repository
// JpaRepository(T, ID),T=資料表的類別(Model),ID=Primary Key的型別
public interface MarketRepository extends JpaRepository<MarketModel, String> {

    // 讀取全部的市場清單
    // nativeQuery = true表示要使用SQL來操作資料
    @Query(value = "SELECT MARKET_NAME, MARKET_CODE FROM STOCK_MARKET.MARKETS;", nativeQuery = true)
    // 將資料存放進一個List回傳
    public List<MarketModel> findAllDetails();

    // 依照市場代碼為條件撈出市場清單
    // MARKET_CODE=:MARKET_CODE,冒號後面表示要帶入的參數
    @Query(value = "SELECT MARKET_NAME, MARKET_CODE FROM STOCK_MARKET.MARKETS WHERE MARKET_CODE=:MARKET_CODE", nativeQuery = true)
    // @Param("MARKET_CODE") String MARKET_CODE,@Param內要與SQL語法內的參數一致,後面的函數參數則可以自訂,通常會一致,比較好辨認
    public List<MarketModel> findByMarketCode(@Param("MARKET_CODE") String MARKET_CODE);
}

步驟6:在Controller資料夾內新增MarketController.java,實作Restful API控制器讀取資料庫的部分。

package stockmarket.jovepater.com.stockmarket.Controllers;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import stockmarket.jovepater.com.stockmarket.Classes.RspBody;
import stockmarket.jovepater.com.stockmarket.Repositories.MarketRepository;

@RestController
public class MarketController {
    // 宣告使用MarketRepository
    @Autowired
    MarketRepository marketRepository;

    @GetMapping("markets")
    public RspBody getAllMarkets() {
        // 呼叫marketRepository.findAllDetails()取得所有市場清單
        return new RspBody("0000", "Success", marketRepository.findAllDetails());
    }

    // 在URL中設定一個名為MARKET_CODE的參數,參數的部分要用{}刮起來
    @GetMapping("market/{MARKET_CODE}")
    // @PathVariable("MARKET_CODE")表示這個參數從URL帶進來,與@GetMapping中定義的名稱要一致
    public RspBody getMarketByMarketCode(@PathVariable("MARKET_CODE") String MARKET_CODE) {
        // 透過marketRepository.findByMarketCode()並帶入參數取得指定市場代碼的市場清單
        return new RspBody("0000", "Success", marketRepository.findByMarketCode(MARKET_CODE));
    }
}

步驟7:呼叫Restful API,可以取得以下結果:

http://127.0.0.1:8080/api/markets
http://127.0.0.1:8080/api/market/TP

取得個股清單(單張表多個Primary Key)

在資料表的處理上,多Primary Key相對於單Primary Key,會需要多宣告一個類別用來定義Primary Key的清單,還有一些小細節。

步驟1:在Models資料夾內新增StockId.java,定義Primary Key。

package stockmarket.jovepater.com.stockmarket.Models;

import java.io.Serializable;

// 實作Serializable
public class StockId implements Serializable {
    private String STOCK_ID;
    private String STOCK_NAME;
    private String MARKET_CODE;
}

步驟2:在Models資料夾內新增StockModel.java,定義資料表的樣子。

package stockmarket.jovepater.com.stockmarket.Models;

import java.io.Serializable;

import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.IdClass;
import javax.persistence.Table;

@Entity
@Table(name = "STOCKS")
// 將參考步驟1對Primary Key的定義
@IdClass(StockId.class)
// 實作Serializable
public class StockModel implements Serializable {
    // 透過多個@Id來指定Primary Key
    @Id
    private String STOCK_ID;
    @Id
    private String STOCK_NAME;
    @Id
    private String MARKET_CODE;

    public StockModel() {
    }

    public StockModel(String STOCK_ID, String STOCK_NAME, String MARKET_CODE) {
        this.STOCK_ID = STOCK_ID;
        this.STOCK_NAME = STOCK_NAME;
        this.MARKET_CODE = MARKET_CODE;
    }

    // getters and setters ...
}

步驟3:接著在Repositories新增StockRepository.java,將資料存取的規則寫入。

package stockmarket.jovepater.com.stockmarket.Repositories;

import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
import stockmarket.jovepater.com.stockmarket.Models.StockId;
import stockmarket.jovepater.com.stockmarket.Models.StockModel;

@Repository
// JpaRepository(T, ID),T=資料表的類別(Model),ID=Primary Key的型別,所以ID的地方要寫StockId,就是定義Primary Key的那個類別,而不是單純的型別
public interface StockRepository extends JpaRepository<StockModel, StockId> {
    @Query(value = "SELECT STOCK_ID, STOCK_NAME, MARKET_CODE FROM STOCK_MARKET.STOCKS ORDER BY STOCK_ID;", nativeQuery = true)
    public List<StockModel> findAllDetails();
}

步驟4:呼叫Restful API,可以取得以下結果:

http://127.0.0.1:8080/api/stocks

相關資源

小結

至此,已經可以從資料庫讀取資料了,特別強調一點,ORM的方便在於操作資料庫,並不代表透過ORM就可以不使用SQL語法,只有非常單純的Use Case才可能完全不使用SQL語法,在大多數的系統開發上,還是要習慣下SQL的,這也是為什麼本篇的範例都還是以SQL語法來讀取資料,特此說明。

~ END ~


, , ,

Related posts

Latest posts