<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    posts - 495,  comments - 11,  trackbacks - 0

    4.8 事 件 機 制

    通常,Hibernate執行持久化過程中,應用程序無法參與其中。所有的數據持久化操作,對用戶都是透明的,用戶無法插入自己的動作。

    通過事件框架,Hibernate允許應用程序能響應特定的內部事件,從而允許實現某些通用的功能,或對Hibernate功能進行擴展。

    Hibernate的事件框架由兩個部分組成:

    ?? ● 攔截器機制,對于特定動作攔截,回調應用中的特定動作。

    ?? ● 事件系統,重寫Hibernate的事件監聽器。

    4.8.1 攔截器

    通過Interceptor接口,可以從Session中回調應用程序的特定方法,這種回調機制可讓應用程序在持久化對象被保存、更新、刪除或加載之前,檢查并修改其屬性。

    通過Interceptor接口,可以在數據進入數據庫之間,對數據進行最后的檢查,如果數據不符合要求,可以修改數據,從而避免非法數據進入數據庫。當然,通常無須這樣做,只是在某些特殊的場合下,才考慮使用攔截器完成檢查功能。

    使用攔截器可按如下步驟進行:

    (1)定義實現Interceptor接口的攔截器類;

    (2)通過Session啟用攔截器,或者通過Configuration啟用全局攔截器。

    下面是一個攔截器的示例代碼,該攔截器沒有進行任何實際的操作,僅僅打印出標志代碼:

    public class MyInterceptor extends EmptyInterceptor

    {

    ??? //更新的次數

    ??? private int updates;

    ??? //插入的次數

    ??? private int creates;

    ??? //刪除數據時,將調用onDelete方法

    ??? public void onDelete(Object entity,Serializable id,Object[]

    ??? state,String[] propertyNames, Type[] types)

    ??? {

    ??????? //do nothing

    ??? }

    ??? //同步Session和數據庫中的數據

    ??? 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;

    ??????? }

    ??? //加載持久化實例時,調用該方法

    ??? public boolean onLoad(Object entity,Serializable id,Object[]

    ??? state,String[] propertyNames,Type[] types)

    ??? {

    ??????? System.out.println("========================");

    ??????? for ( int i=0; i < propertyNames.length; i++ )

    ??????? {

    ??????????? if ( "name".equals( propertyNames[i] ) )

    ??????????? {

    ??????????????? System.out.println(state[i]);

    ??????????????? state[i] = "aaa";

    ??????????????? 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;

    ??? }

    ??? //提交刷新

    ??? public void postFlush(Iterator entities)

    ??? {

    ??????? System.out.println("創建的次數: " + creates + ", 更新的次數: " +

    ??? updates);

    ??? }

    ??? public void preFlush(Iterator entities)

    ??? {

    ??????? updates=0;

    ??????? creates=0;

    ??? }

    ??? //事務提交前,觸發該方法

    ??? public void beforeTransactionCompletion(Transaction tx)

    ??? {

    ??????? System.out.println("事務即將結束");

    ??? }

    ??? //事務提交后,觸發該方法

    ??? public void afterTransactionCompletion(Transaction tx)

    ??? {

    ??????? System.out.println("事務已經結束");

    ??? }

    }

    在上面的攔截器實現類中,實現了很多方法,這些方法都是在Hibernate執行特定動作時自動調用。

    完成了攔截器的定義,下面是關于攔截器的使用。攔截器的使用有兩種方法:

    ?? ● 通過SessionFactory的openSession(Interceptor in)方法打開一個帶局部攔截器的Session。

    ?? ● 通過Configuration的setInterceptor(Interceptor in)方法設置全局攔截器。

    下面是使用局部攔截器的示例代碼:

    public class HibernateUtil

    {

    ??? //靜態類屬性 SessionFactory

    ??? public static final SessionFactory sessionFactory;

    ??? //靜態初始化塊,完成靜態屬性的初始化

    ??? static

    ??? {

    ??????? try

    ??????? {

    ??????????? //采用默認的hibernate.cfg.xml來啟動一個Configuration的實例

    ??????????? Configuration configuration=new Configuration().configure();

    ??????????? //由Configuration的實例來創建一個SessionFactory實例

    ??????????? sessionFactory = configuration.buildSessionFactory();

    ??????? }

    ??????? catch (Throwable ex)

    ??????? {

    ??????????? System.err.println("初始化sessionFactory失敗." + ex);

    ??????????? throw new ExceptionInInitializerError(ex);

    ??????? }

    ??? }

    ??? //ThreadLocal是隔離多個線程的數據共享,不存在多個線程之間共享資源,因此不再需要

    ??? 對線程同步???

    ??? public static final ThreadLocal session = new ThreadLocal();

    ??? //不加攔截器的打開Session方法

    ??? public static Session currentSession() throws HibernateException

    ??? {

    ??????? Session s = (Session) session.get();

    ??????? //如果該線程還沒有Session,則創建一個新的Session

    ??????? if (s == null)

    ??????? {

    ??????????? s = sessionFactory.openSession();

    ??????????? //將獲得的Session變量存儲在ThreadLocal變量的Session里

    ??????????? session.set(s);

    ??????? }

    ??????? return s;

    ??? }

    ??? //加攔截器的打開Session方法

    ??? public static Session currentSession(Interceptor it) throws

    ??? HibernateException

    ??? {

    ??????? Session s = (Session) session.get();

    ??????? //如果該線程還沒有Session,則創建一個新的Session

    ??????? if (s == null)

    ??????? {

    ??????????? //以攔截器創建Session對象

    ??????? ??? s = sessionFactory.openSession(it);

    ??????????? //將獲得的Session變量存儲在ThreadLocal變量的Session里

    ??????????? session.set(s);

    ??????????? }

    ??????? return s;

    ??? }

    ??? //關閉Session對象

    ??? public static void closeSession() throws HibernateException

    ??? {

    ??????? Session s = (Session) session.get();

    ??????? if (s != null)

    ??? ??????? s.close();

    ??????? session.set(null);

    ??? }

    }

    上面的Hibernate工具類提供了兩個currentSession方法,分別用于不使用攔截器獲取Session對象和使用攔截器獲取Session對象。

    下面是主程序使用攔截器的代碼片段:

    private void testUser()

    {

    ??? //以攔截器開始Session

    ??? Session session = HibernateUtil.currentSession(new MyInterceptor());

    ??? //開始事務

    ??? Transaction tx = session.beginTransaction();

    ??? //執行下面的代碼時,可以看到系統回調onSave等方法

    ??? /*

    ??? User u = new User();

    ??? u.setName("Yeeku Lee");

    ??? u.setAge(28);

    ??? u.setNationality("中國");

    ??? session.persist(u);

    ??? u.setAge(29);

    ??? u.setAge(30);

    ??? session.persist(u);

    ??? */

    ??? //執行下面的代碼時,可以看到系統回調onLoad等方法

    ??? Object o = session.load(User.class , new Integer(1));

    ??? System.out.println(o);

    ??? User u = (User)o;

    ??? System.out.println(u.getName());

    ??? //提交事務時,可以看到系統回調事務相關方法

    ??? tx.commit();

    ??? HibernateUtil.closeSession();

    }

    4.8.2 事件系統

    Hibernate 3的事件系統是功能更強大的事件框架,事件系統可以替代攔截器,也可以作為攔截器的補充來使用。

    基本上,Session接口的每個方法都有對應的事件。如LoadEvent和FlushEvent等。當Session調用某個方法時,Hibernate Session會生成對應的事件,并激活對應的事件監聽器。

    系統默認監聽器實現的處理過程,完成了所有的數據持久化操作,包括插入和修改等操作。如果用戶定義了自己的監聽器,則意味著用戶必須完成對象的持久化操作。

    例如,可以在系統中實現并注冊LoadEventListener監聽器,該監聽器負責處理所有調用Session的load()方法的請求。

    監聽器是單態模式對象,即所有同類型的事件處理共享同一個監聽器實例,因此監聽器不應該保存任何狀態,即不應該使用成員變量。

    使用事件系統可按如下步驟進行:

    (1)實現自己的事件監聽器類;

    (2)注冊自定義事件監聽器,代替系統默認的事件監聽器。

    實現用戶的自定義監聽器有如下3個方法:

    ?? ● 實現對應的監聽器接口,這是不可思議的,實現接口必須實現接口內的所有方法,關鍵是必須實現Hibernate對應的持久化操作,即數據庫訪問,這意味著程序員完全取代了Hibernate的底層操作。

    ?? ● 繼承事件適配器,可以選擇性地實現需要關注的方法,但依然試圖取代Hibernate完成數據庫的訪問,這也不太現實。

    ?? ● 繼承系統默認的事件監聽器,擴展特定方法。

    實際上,前兩種方法很少使用。因為Hibernate的持久化操作也是通過這些監聽器實現的,如果用戶取代了這些監聽器,則應該自己實現所有的持久化操作,這意味著用戶放棄了Hibernate的持久化操作,而改為自己完成Hibernate的核心操作。

    通常推薦采用第三種方法實現自己的事件監聽器。Hibernate默認的事件監聽器都被聲明成non-final,從而方便用戶繼承。

    下面是用戶自定義監聽器的示例:

    //自定義LoadListener,繼承默認的DefaultLoadEventListener實現類

    public class MyLoadListener extends DefaultLoadEventListener

    {

    ??? //在LoadEventListener接口僅僅定義了這個方法

    ??? public Object onLoad(LoadEvent event, LoadEventListener.LoadType

    ??? loadType)throws HibernateException

    ??? {

    ??????? //先調用父類的onLoad方法,從而完成默認的持久化操作

    ??????? Object o = super.onLoad(event, loadType);

    ??????? //加入用戶的自定義處理

    ??????? System.out.println("自定義的load事件");

    ??????? System.out.println(event.getEntityClassName() + "==========" +

    ??????? event.getEntityId());

    ??????? return o;

    ??? }

    }

    下面還有一個MySaveListener,用于監聽SaveEvent事件:

    //自定義SavaListener,繼承默認的DefaultSaveEventListener實現類

    public class MySaveListener extends DefaultSaveEventListener

    {

    ??? //該方法完成實際的數據插入動作

    ??? protected Serializable performSaveOrUpdate(SaveOrUpdateEvent event)

    ??? {

    ??????? //先執行用戶自定義的操作

    ??????? System.out.println(event.getObject());

    ??????? //調用父類的默認持久化操作

    ??????? return super.performSaveOrUpdate(event);

    ??? }

    }

    注意:擴展用戶自定義監聽器時,別忘了在方法中調用父類的對應方法。

    注冊用戶自定義監聽器也有兩種方法:

    ?? ● 編程式,通過使用Configuration對象編程注冊。

    ?? ● 聲明式,在Hibernate的XML格式配置文件中進行聲明,使用Properties格式的配置文件將無法配置自定義監聽器。

    下面的示例代碼,通過編程方式使用自定義監聽器:

    public class HibernateUtil2

    {

    ??? //靜態類屬性 SessionFactory

    ??? public static final SessionFactory sessionFactory;

    ??? //靜態初始化塊,完成靜態屬性的初始化

    ??? static

    ??? {

    ??????? try

    ??????? {

    ??????????? Configuration cfg = new Configuration();

    ??????????? //注冊loadEventListener監聽器

    ??????????? cfg.getSessionEventListenerConfig().setLoadEventListener

    ??????????? ( new MyLoadListener() );

    ??????????? //注冊saveListener監聽器

    ??????????? cfg.getSessionEventListenerConfig().setSaveEventListener

    ??????????? (new MySaveListener() );

    ??????????? //由Configuration實例來創建一個SessionFactory實例

    ??????????? sessionFactory = cfg.configure().buildSessionFactory();

    ??????? }

    ??????? catch (Throwable ex)

    ??????? {

    ??????????? System.err.println("初始化sessionFactory失敗." + ex);

    ??????????? throw new ExceptionInInitializerError(ex);

    ??????? }

    ??? }

    ??? //ThreadLocal是隔離多個線程的數據共享,不存在多個線程之間共享資源,因此不再需要

    ??? 對線程同步

    ??? public static final ThreadLocal session = new ThreadLocal();

    ??? //不加攔截器的打開Session方法

    ??? public static Session currentSession() throws HibernateException

    ??? {

    ??????? Session s = (Session) session.get();

    ??????? //如果該線程還沒有Session,則創建一個新的Session

    ??????? if (s == null)

    ??????? {

    ??????????? s = sessionFactory.openSession();

    ??? ??????? //將獲得的Session變量存儲在ThreadLocal變量的Session里

    ??????????? session.set(s);

    ??????? }

    ??????? return s;

    ??? }

    ??? //關閉Session對象

    ??? public static void closeSession() throws HibernateException

    ??? {

    ??????? Session s = (Session) session.get();

    ??????? if (s != null)

    ??????????? s.close();

    ??????? session.set(null);

    ??? }

    }

    如果不想修改代碼,也可以在配置文件中使用事件監聽器,注冊事件監聽器的Hibernate配置文件代碼如下:

    <?xml version='1.0' encoding='GBK'?>

    <!-- Hibernate配置文件的文件頭,包含DTD等信息 -->

    <!DOCTYPE hibernate-configuration PUBLIC

    ??????? "-//Hibernate/Hibernate Configuration DTD 3.0//EN"

    ??????? "http://hibernate.sourceforge.net/hibernate-configuration-3.0.

    ??????? dtd">

    <!-- Hibernate配置文件的根元素 -->

    <hibernate-configuration>

    ??? <session-factory>

    ??????? <!—設置數據庫驅動 -->

    ??????? <property name="connection.driver_class">com.mysql.jdbc.Driver

    ??????? </property>

    ??????? <!-- 數據庫服務的url -->

    ??? ??? <property name="connection.url">jdbc:mysql://localhost/hibernate

    ??????? </property>

    ??????? <!-- 數據庫服務的用戶名 -->

    ??????? <property name="connection.username">root</property>

    ??????? <!-- 數據庫服務的密碼 -->

    ??????? <property name="connection.password">32147</property>

    ??????? <!-- JDBC connection pool (use the built-in) -->

    ??????? <property name="connection.pool_size">5</property>

    ??????? <!-- 設置數據庫方言 -->

    ??????? <property name="dialect">org.hibernate.dialect.MySQLDialect

    ??????? </property>

    ??????? <!-- 顯示Hibernate生成的SQL語句 -->

    ??????? <property name="show_sql">true</property>

    ??????? <!-- 配置應用啟動時,是否啟動自動建表 -->

    ??????? <property name="hbm2ddl.auto">update</property>

    ??????? <!-- 列出所有的持久化映射文件 -->

    ??????? <mapping resource="User.hbm.xml"/>

    ??????? <!-- 注冊事件監聽器 -->

    ??? ??? <listener type="load" class="lee.MyLoadListener"/>

    ??? ??? <listener type="save" class="lee.MySaveListener"/>

    ??? </session-factory>

    </hibernate-configuration>

    使用配置文件注冊事件監聽器雖然方便,但也有不利之處,通過配置文件注冊的監聽器不能共享實例。如果多個<listener/>元素中使用了相同的類,則每一個引用都將產生一個新的攔截器實例。如果需要在多個事件之間共享監聽器的實例,則必須使用編程方式注冊事件監聽器。

    注意:雖然監聽器類實現了特定監聽器的接口,在注冊的時候還要明確指出注冊的事件。這是因為一個類可能實現多個監聽器的接口,注冊時明確指定要監聽的事件,可以使得啟用或者禁用某個事件監聽的配置工作更簡單。

    posted on 2009-07-19 09:42 jadmin 閱讀(90) 評論(0)  編輯  收藏

    只有注冊用戶登錄后才能發表評論。


    網站導航:
    博客園   IT新聞   Chat2DB   C++博客   博問  
     
    主站蜘蛛池模板: 一级毛片aa高清免费观看| 亚洲av乱码一区二区三区香蕉| 亚洲狠狠成人综合网| 日韩精品久久久久久免费| 免费av一区二区三区| 亚洲人成伊人成综合网久久久| 美女视频黄.免费网址| 四虎影视永久免费视频观看| 亚洲熟女综合一区二区三区| 成全视频在线观看免费高清动漫视频下载 | 亚洲第一中文字幕| 丝瓜app免费下载网址进入ios| 亚洲男同帅GAY片在线观看| a级毛片100部免费观看| 亚洲爆乳无码一区二区三区| 久久香蕉国产线看免费| 亚洲中文字幕人成乱码| 成人免费毛片观看| 自拍偷自拍亚洲精品偷一| 亚洲国产高清在线一区二区三区| 爱情岛论坛免费视频| 伊人久久大香线蕉亚洲| 日本免费一区二区三区四区五六区| 亚洲国产精品综合一区在线 | 国产精品高清全国免费观看| 国产精品亚洲五月天高清| 亚洲一区日韩高清中文字幕亚洲| 男女一边摸一边做爽的免费视频| 亚洲视频在线播放| 国产香蕉九九久久精品免费| 国产亚洲精品2021自在线| 国产亚洲精品高清在线| 2015日韩永久免费视频播放| 中文字幕亚洲激情| 久久免费精品视频| 亚洲中文字幕无码爆乳app| 国产免费拔擦拔擦8x| 精品免费视在线观看| 亚洲 日韩 色 图网站| 4338×亚洲全国最大色成网站| 91人人区免费区人人|