使用 JPA 和 Spring Boot 呼叫自訂資料庫函數
1. 概述
資料庫函數是資料庫管理系統中的重要元件,可以將邏輯和執行封裝在資料庫中。它們促進高效的數據處理和操作。
在本教程中,我們將探索在 JPA 和 Spring Boot 應用程式中呼叫自訂資料庫函數的各種方法。
2. 項目設定
我們將在後續部分中使用 H2 資料庫來示範這些概念。
讓我們在pom.xml
中包含Spring Boot Data JPA和H2依賴項:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<version>3.2.2</version>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>2.2.224</version>
</dependency>
3. 資料庫功能
資料庫函數是透過在資料庫中執行一組 SQL 語句或操作來執行特定任務的資料庫物件。當邏輯是資料密集型時,這可以提高效能。儘管資料庫函數和預存程序的操作類似,但它們卻存在差異。
3.1.函數與預存程序
雖然不同的資料庫系統之間可能存在特定的差異,但它們之間的主要差異可以總結為下表:
特徵 | 資料庫功能 | 儲存過程 |
---|---|---|
祈求 | 可以在查詢中調用 | 必須顯式調用 |
傳回值 | 始終傳回單一值 | 可能不傳回、單一或多個值 |
範圍 | 僅支援輸入參數 | 支援輸入和輸出參數 |
呼喚 | 無法使用函數呼叫預存程序 | 可以使用預存程序呼叫函數 |
用法 | 通常執行計算或資料轉換 | 通常用於複雜的業務邏輯 |
3.2. H2功能
為了說明從 JPA 呼叫資料庫函數,我們將在 H2 中建立一個資料庫函數來說明如何從 JPA 呼叫它。 H2資料庫函數只是嵌入的Java原始碼,將被編譯執行:
CREATE ALIAS SHA256_HEX AS '
import java.sql.*;
@CODE
String getSha256Hex(Connection conn, String value) throws SQLException {
var sql = "SELECT RAWTOHEX(HASH(''SHA-256'', ?))";
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
stmt.setString(1, value);
ResultSet rs = stmt.executeQuery();
if (rs.next()) {
return rs.getString(1);
}
}
return null;
}
';
此資料庫函數SHA256_HEX
接受單一輸入參數作為字串,透過SHA-256雜湊演算法對其進行處理,然後傳回其 SHA-256 雜湊的十六進位表示法。
4. 作為預存程序調用
第一種方法是呼叫類似 JPA 中的預存程序的資料庫函數。我們透過@NamedStoredProcedureQuery
註解實體類別來完成它。此註解允許我們直接在實體類別中指定預存程序的元資料。
以下是具有定義的預存程序SHA256_HEX
的Product
實體類別的範例:
@Entity
@Table(name = "product")
@NamedStoredProcedureQuery(
name = "Product.sha256Hex",
procedureName = "SHA256_HEX",
parameters = @StoredProcedureParameter(mode = ParameterMode.IN, name = "value", type = String.class)
)
public class Product {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "product_id")
private Integer id;
private String name;
// constructor, getters and setters
}
在實體類別中,我們使用@NamedStoredProcedureQuery
註解我們的Product
實體類別。我們將Product.sha256Hex
指定為命名預存程序的名稱。
在我們的儲存庫定義中,我們使用@Procedure
註解儲存庫方法,並引用@NamedStoredProcedureQuery
的名稱。此儲存庫方法採用字串參數,然後將其提供給資料庫函數,並傳回資料庫函數呼叫的結果。
public interface ProductRepository extends JpaRepository<Product, Integer> {
@Procedure(name = "Product.sha256Hex")
String getSha256HexByNamed(@Param("value") String value);
}
我們將看到 Hibernate 呼叫它就像在執行時從 Hibernate 日誌呼叫預存程序一樣:
Hibernate:
{call SHA256_HEX(?)}
@NamedStoredProcedureQuery
主要用於呼叫預存程序。資料庫函數可以單獨調用,也類似於預存程序。但是,對於與選擇查詢結合使用的資料庫函數來說,它可能並不理想。
5. 原生查詢
呼叫資料庫函數的另一種方法是透過本機查詢。使用本機查詢呼叫資料庫函數有兩種不同的方法。
5.1.本地調用
從前面的Hibernate日誌中,我們可以看到Hibernate執行了一條CALL
指令。同樣,我們可以使用相同的命令本地呼叫我們的資料庫函數:
public interface ProductRepository extends JpaRepository<Product, Integer> {
@Query(value = "CALL SHA256_HEX(:value)", nativeQuery = true)
String getSha256HexByNativeCall(@Param("value") String value);
}
執行結果將與我們在使用@NamedStoredProcedureQuery.
5.2.本機選擇
正如我們之前所描述的,我們不能將它與選擇查詢結合使用。我們將其切換為選擇查詢並將該函數應用於表中的列值。在我們的範例中,我們定義了一個儲存庫方法,該方法使用本機選擇查詢來呼叫Product
表的name
列上的資料庫函數:
public interface ProductRepository extends JpaRepository<Product, Integer> {
@Query(value = "SELECT SHA256_HEX(name) FROM product", nativeQuery = true)
String getProductNameListInSha256HexByNativeSelect();
}
執行後,我們可以從 Hibernate 日誌中取得與我們定義相同的查詢,因為我們將其定義為本機查詢:
Hibernate:
SELECT
SHA256_HEX(name)
FROM
product
6. 函數註冊
函數註冊是定義和註冊可在 JPA 或 Hibernate 查詢中使用的自訂資料庫函數的 Hibernate 程序。這有助於 Hibernate 將自訂函數翻譯成對應的 SQL 語句。
6.1.自訂方言
我們可以透過建立自訂方言來註冊自訂函數。這是擴展預設H2Dialect
並註冊我們的函數的自訂方言類別:
public class CustomH2Dialect extends H2Dialect {
@Override
public void initializeFunctionRegistry(FunctionContributions functionContributions) {
super.initializeFunctionRegistry(functionContributions);
SqmFunctionRegistry registry = functionContributions.getFunctionRegistry();
TypeConfiguration types = functionContributions.getTypeConfiguration();
new PatternFunctionDescriptorBuilder(registry, "sha256hex", FunctionKind.NORMAL, "SHA256_HEX(?1)")
.setExactArgumentCount(1)
.setInvariantType(types.getBasicTypeForJavaType(String.class))
.register();
}
}
當Hibernate初始化一個方言時,它透過initializeFunctionRegistry()
將可用的資料庫函數註冊到函數註冊表。我們重寫initializeFunctionRegistry()
方法來註冊其他預設方言不包含的資料庫函數。
PatternFunctionDescriptorBuilder
建立一個 JPQL 函數映射,將我們的資料庫函數SHA256_HEX
映射到 JPQL 函數sha256Hex
並將該映射註冊到函數註冊表。參數?1
指示資料庫函數的第一個輸入參數。
6.2.休眠配置
我們必須指示 Spring Boot 採用CustomH2Dialect
而不是預設的H2Dialect
。這裡HibernatePropertiesCustomizer
就位了。它是 Spring Boot 提供的一個接口,用於自訂 Hibernate 使用的屬性。
我們重寫customize()
方法來新增一個額外的屬性來指示我們將使用CustomH2Dialect
:
@Configuration
public class CustomHibernateConfig implements HibernatePropertiesCustomizer {
@Override
public void customize(Map<String, Object> hibernateProperties) {
hibernateProperties.put("hibernate.dialect", "com.baeldung.customfunc.CustomH2Dialect");
}
}
Spring Boot 在應用程式啟動期間自動偵測並套用自訂。
6.3.儲存庫方法
在我們的儲存庫中,我們現在可以使用應用新定義的函數sha256Hex
的 JPQL 查詢,而不是本機查詢:
public interface ProductRepository extends JpaRepository<Product, Integer> {
@Query(value = "SELECT sha256Hex(p.name) FROM Product p")
List<String> getProductNameListInSha256Hex();
}
當我們在執行時檢查 Hibernate 日誌時,我們看到 Hibernate 正確地將 JPQL sha256Hex
函數轉換為我們的資料庫函數SHA256_HEX
:
Hibernate:
select
SHA256_HEX(p1_0.name)
from
product p1_07'
七、結論
在本文中,我們對資料庫函數和預存程序進行了簡要比較。兩者都提供了封裝邏輯並在資料庫中執行的強大方法。
此外,我們也探索了呼叫資料庫函數的不同方法,包括利用@NamedStoredProcedureQuery
註解、本機查詢和透過自訂方言進行函數註冊。透過將資料庫功能合併到儲存庫方法中,我們可以輕鬆建立資料庫驅動的應用程式。
與往常一樣,提供所討論概念的實用資源的範例可在 GitHub 上找到。