Hibernate執行持久化過程中,應用程序無法參與其中。所有的數據持久化操作,對用戶都是透明的。
通過事件框架,Hibernate允許應用程能響應特定的內部事件,從而允許實現某些通用的功能或者對Hibernate功能進行擴展。
Hibernate的事件機制框架由兩個部分組成:
1、攔截器機制:對於特定動作攔截,回調應用中的特定動作
2、事件系統:重寫Hibernate的事件監聽器。
一、攔截器
Interceptor接口提供瞭從會話回調應用程序的機制,這種回調機制可以允許應用程序在持久化對象被保存、更新、刪除或是加載之前,檢查並(或)修改其屬性。
通過Interceptor接口,可以在數據進入數據庫之前,對數據進行最後的檢查,如果數據不符合要求,可以修改數據,從而避免非法數據進入數據庫。
使用攔截器按如下兩個步驟進行:
1、定義實現Interceptor接口的攔截器
2、通過Session啟用攔截器,或者通過Configuration啟用全局攔截器
程序可以通過實現Interceptor接口來創建攔截器,也可以通過繼承EmptyInterceptor來實現攔截器。
[java]
public class MyIterceptor extends EmptyInterceptor {
// 記錄修改次數
private int updates;
// 記錄創建次數
private int creates;
// 當刪除實體時,onDelete方法將被調用
public void onDelete(Object entity, Serializable id, Object[] state,
String[] propertyNames, Type[] types) {
// do nothing
}
// 當把持久化實體的狀態同步到數據庫時,onFlushDirty方法被調用
public boolean onFlushDirty(Object entity, Serializable id,
Object[] currentState, Object[] previousState,
String[] propertyNames, Type[] types) {
// 每同步一次,修改的累加器加1
updates++;
for (int i = 0; i < propertyNames.length; i++) {
if ("lastUpdateTimestamp".equals(propertyNames[i])) {
currentState[i] = new Date();
return true;
}
}
return false;
}
// 當加載持久化實體時,onLoad方法被調用
public boolean onLoad(Object entity, Serializable id, Object[] state,
String[] propertyNames, Type[] types) {
for (int i = 0; i < propertyNames.length; i++) {
if ("name".equals(propertyNames[i])) {
// 輸出被裝載實體的name屬性值
System.out.println(state[i]);
return true;
}
}
return false;
}
// 保存持久化實例時候,調用該方法
public boolean onSave(Object entity, Serializable id, Object[] state,
String[] propertyNames, Type[] types) {
creates++;
for (int i = 0; i < propertyNames.length; i++) {
if ("createTimestamp".equals(propertyNames[i])) {
state[i] = new Date();
return true;
}
}
return false;
}
// 持久化所做修改同步完成後,調用postFlush方法
public void postFlush(Iterator entities) {
System.out.println("創建的次數: " + creates + ", 更新的次數: " + updates);
}
// 在同步持久化所做修改之前,調用preFlush方法
public void preFlush(Iterator entities) {
}
// 事務提交之前觸發該方法
public void beforeTransactionCompletion(Transaction tx) {
System.out.println("事務即將結束");
}
// 事務提交之後觸發該方法
public void afterTransactionCompletion(Transaction tx) {
System.out.println("事務已經結束");
}
}
上面攔截器沒有進行實際的操作,隻是打印瞭一些標識代碼。
攔截器可以有兩種:Session范圍內的,和SessionFactory范圍內的。
當使用某個重載的SessionFactory.openSession()使用Interceptor作為參數調用打開一個session的時候,就指定瞭Session范圍內的攔截器。
[java]
Session session = sf.openSession( new MyInterceptor() );
SessionFactory范圍內的攔截器要通過Configuration中註冊,而這必須在創建SessionFactory之前。在這種情況下,給出的攔截器會被這個SessionFactory所打開的所有session使用瞭
[java]
new Configuration().setInterceptor( new MyInterceptor() );
示例:
[java]
public void newsTest(){
Configuration cfg = new Configuration().configure().setInterceptor(new MyIterceptor());
SessionFactory sf = cfg.buildSessionFactory();
Session session = sf.openSession();
Transaction tx = session.beginTransaction();
//創建一個News對象
News news = new News();
news.setTitle("搬校區瞭..");
news.setContent("明天我們就要搬校區瞭,真期待啊….");
session.save(news);
News news2 = (News) session.load(News.class, 1);
news2.setTitle("明天就要搬校區瞭..");
tx.commit();
session.close();
}
程序運行結果如下:
二、事件機制
如果需要響應持久層的某些特殊事件,可以使用Hibernate3的事件框架。該事件系統可以用來替代攔截器,也可以作為攔截器的補充來使用。
Session接口的每個方法都有相對應的事件。比如 LoadEvent,FlushEvent,等等。當某個方法被調用時,Hibernate Session會生成一個相對應的事件並激活所有配置好的事件監聽器。
系統默認監聽器實現的處理過程,完成瞭所有的數據持久化操作,包括插入、修改等操作。如果用戶自己定義瞭自己的監聽器,則意味著用戶必須完成對象的持久化操作。
監聽器是單例模式對象,即所有同類型的事件處理共享同一個監聽器實例,因此監聽器不應該保存任何狀態,即不應該使用成員變量。
使用事件系統按如下步驟:
1、實現自己的事件監聽器
2、註冊自定義事件監聽器,代替系統默認的事件監聽器
實現用戶的自定義監聽器有如下三種方法:
1、實現對應的監聽器接口。實現接口必須實現接口內的所有方法,關鍵是必須事件Hibernate對應的持久化操作,即數據庫訪問,這意味著程序員完全取代瞭Hibernate的底層操作。
2、繼承事件適配器。可以選擇性地實現需要關註的方法,但依然試圖取代Hibernate完成數據庫的訪問。
3、繼承系統默認的事件監聽器。擴展特定方法。
下面是自定義監聽器實例:
[java]
public class MyLoadListener extends DefaultLoadEventListener {
//在LoadEventListener接口僅僅定義瞭這個方法
public void onLoad(LoadEvent event,LoadEventListener.LoadType loadType) throws HibernateException{
System.out.println("自定義的load事件");
System.out.println(event.getEntityClassName()+"——"+event.getEntityId());
super.onLoad(event, loadType);
}
}
[html]
public class MySaveListener extends DefaultSaveEventListener{
protected Serializable performSaveOrUpdate(SaveOrUpdateEvent event){
System.out.println("自定義的save事件");
System.out.println(event.getObject());
return super.performSaveOrUpdate(event);
}
}
<span style="font-size:16px;"><span style="font-size:16px;"> </span></span>
註意:擴展用戶自定義監聽器時,別忘瞭在方法中調用父類的對應的方法,否則Hibernate3默認的持久化行為都會失效。
註冊用戶自定義監聽器有兩種方法:
1、編程式。通過使用Configuration對象來編程實現註冊。
[java]
public void newsListenerTest(){
Configuration conf = new Configuration().configure();
//為load事件設置監聽器
conf.setListener("load", "com.hibernate.filter.MyLoadListener");
conf.setListener("save", "com.hibernate.filter.MySaveListener");
SessionFactory sfg = conf.buildSessionFactory();
Session session = sfg.openSession();
Transaction tx = session.beginTransaction();
News news = new News();
news.setContent("2222");
news.setTitle("1111");
session.save(news); //調用save方法,觸動save監聽器
tx.commit();
session.load(News.class, 1); //調用load方法,觸動load監聽器
session.close();
}
2、聲明式。在hibernate.cfg.xml配置文件中進行聲明。
註冊事件監聽器使用<listener…/>元素。該元素可以接受兩個參數。type:指定該事件監聽器所監聽的事件類型,class:指定事件監聽器的實現類 www.aiwalls.com
[html]
<listener class="com.hibernate.listener.MyLoadListener" type="load"/>
<listener class="com.hibernate.listener.MySaveListener" type="save"/>
如果需要為指定事件配置多個事件監聽器,則需要使用<event…/>元素。在<event…/>元素裡可以使用多個<listener…/>子元素來指定多個事件監聽器。
[html]
<event type="save">
<listener class="com.hibernate.listener.MySaveListener"/>
<listener class="com.hibernate.listener.MyLoadListener"/>
</event>
作者:chenssy