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,可以取得以下結果:
取得個股清單(單張表多個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,可以取得以下結果:
相關資源
小結
至此,已經可以從資料庫讀取資料了,特別強調一點,ORM的方便在於操作資料庫,並不代表透過ORM就可以不使用SQL語法,只有非常單純的Use Case才可能完全不使用SQL語法,在大多數的系統開發上,還是要習慣下SQL的,這也是為什麼本篇的範例都還是以SQL語法來讀取資料,特此說明。
~ END ~