Hibernate讀書筆記—–事件機制 – JAVA編程語言程序開發技術文章

   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

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。