在 Hibernate 框架中,Interceptor 介面提供了一種強大的機制,允許開發者在物件持久化的生命週期中插入自定義邏輯。這與 Struts 2 的攔截器概念類似,都能在特定操作前後執行橫切關注點,如日誌記錄、資料審計或自動填充欄位。
實作 org.hibernate.Interceptor 介面時,最常覆寫的方法包括:
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 提供多種集合映射型別,對應 Java Collections Framework,但行為上有關鍵差異,尤其在處理重複值與排序時。
映射 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 會去重,導致資料遺失;刪除時會刪除所有相同值的記錄。
映射 java.util.List 或 Collection,不檢查重複,但無法精確刪除單筆記錄(會刪除同 user_id 下所有記錄)。
<bag name="addresses" table="t_address" lazy="true">
<key column="user_id"/>
<element column="address" type="string"/>
</bag>
為集合表新增獨立主鍵 <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=?,精確移除目標記錄。
透過 <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 會自動更新索引欄位。
對應 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 | 是 | 是 | 是 | 需保留順序的列表 |
| Map | Key不可重複 | 否 | 是 | 鍵值對關聯資料 |