首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

深入解析 Hibernate Interceptor 與 Collection 集合映射機制

     編輯:Java 相關知識

Hibernate Interceptor:攔截器的核心應用

在 Hibernate 框架中,Interceptor 介面提供了一種強大的機制,允許開發者在物件持久化的生命週期中插入自定義邏輯。這與 Struts 2 的攔截器概念類似,都能在特定操作前後執行橫切關注點,如日誌記錄、資料審計或自動填充欄位。

核心方法解析

實作 org.hibernate.Interceptor 介面時,最常覆寫的方法包括:

  • onSave():物件首次儲存前觸發,可修改屬性值(如自動添加前綴)。
  • onLoad():物件從資料庫載入時觸發,可對讀取的資料進行轉換(如解密、格式化)。
  • onPrepareStatement():SQL 語句準備階段觸發,可攔截並記錄即將執行的 SQL。

實戰範例:自動添加名稱前綴

public class MyInterceptor implements Interceptor {
    @Override
    public boolean onSave(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) {
        if (entity instanceof User) {
            User user = (User) entity;
            user.setName("123" + user.getName()); // 在儲存前修改名稱
            // 必須同步更新 state 陣列,否則資料庫不會持久化修改
            for (int i = 0; i < propertyNames.length; i++) {
                if ("name".equals(propertyNames[i])) {
                    state[i] = user.getName();
                    break;
                }
            }
            return true; // 返回 true 表示 state 已修改
        }
        return false;
    }
    
    @Override
    public boolean onLoad(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) {
        if (entity instanceof User) {
            // 載入時移除前綴
            for (int i = 0; i < propertyNames.length; i++) {
                if ("name".equals(propertyNames[i]) && state[i] instanceof String) {
                    String val = (String) state[i];
                    if (val.startsWith("123")) {
                        state[i] = val.substring(3);
                    }
                    break;
                }
            }
        }
        return false;
    }
}

啟用攔截器

Configuration cfg = new Configuration().configure();
SessionFactory sf = cfg.buildSessionFactory();
Interceptor interceptor = new MyInterceptor();
Session session = sf.openSession(interceptor); // 綁定攔截器到 Session

Hibernate 集合映射:Set、Bag、List、Map 詳細比較

Hibernate 提供多種集合映射型別,對應 Java Collections Framework,但行為上有關鍵差異,尤其在處理重複值與排序時。

1. <set> - 不允許重複,無序

映射 java.util.Set,底層依賴 equals() 和 hashCode() 判斷唯一性。

<set name="addresses" table="t_address" cascade="all">
    <key column="user_id"/>
    <element column="address" type="string"/>
</set>

陷阱:若元素為 String 且值相同,Set 會去重,導致資料遺失;刪除時會刪除所有相同值的記錄。

2. <bag> - 允許重複,無序

映射 java.util.List 或 Collection,不檢查重複,但無法精確刪除單筆記錄(會刪除同 user_id 下所有記錄)。

<bag name="addresses" table="t_address" lazy="true">
    <key column="user_id"/>
    <element column="address" type="string"/>
</bag>

3. <idbag> - 允許重複,有代理鍵,可精確刪除

為集合表新增獨立主鍵 <collection-id>,解決 Bag 無法精確刪除的問題。

<idbag name="addresses" table="t_address" lazy="true">
    <collection-id column="id" type="int">
        <generator class="identity"/>
    </collection-id>
    <key column="user_id"/>
    <element column="address" type="string"/>
</idbag>

刪除時生成:DELETE FROM t_address WHERE id=?,精確移除目標記錄。

4. <list> - 允許重複,有序(保留索引)

透過 <index> 維護順序,適合需保留插入順序的場景。

<list name="addresses" table="t_address" lazy="true">
    <key column="user_id"/>
    <index column="idx" type="int"/>
    <element column="address" type="string"/>
</list>

可透過 list.set(0, newValue) 交換位置,Hibernate 會自動更新索引欄位。

5. <map> - 鍵值對映射

對應 java.util.Map,需指定 <index> 作為 Key。

<map name="addresses" table="t_address" lazy="true">
    <key column="user_id"/>
    <index column="type" type="string"/> <!-- Map 的 Key -->
    <element column="address" type="string"/> <!-- Map 的 Value -->
</map>

相同 Key 會覆蓋,僅保留最後一筆。

選型建議

集合型別允許重複有序精確刪除適用場景
Set否否是唯一值集合,如標籤、權限
Bag是否否簡單列表,不需精確刪除
IdBag是否是需精確刪除的列表
List是是是需保留順序的列表
MapKey不可重複否是鍵值對關聯資料
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved