<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 事 件 機(jī) 制

    通常,Hibernate執(zhí)行持久化過程中,應(yīng)用程序無法參與其中。所有的數(shù)據(jù)持久化操作,對用戶都是透明的,用戶無法插入自己的動作。

    通過事件框架,Hibernate允許應(yīng)用程序能響應(yīng)特定的內(nèi)部事件,從而允許實現(xiàn)某些通用的功能,或?qū)ibernate功能進(jìn)行擴(kuò)展。

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

    ?? ● 攔截器機(jī)制,對于特定動作攔截,回調(diào)應(yīng)用中的特定動作。

    ?? ● 事件系統(tǒng),重寫Hibernate的事件監(jiān)聽器。

    4.8.1 攔截器

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

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

    使用攔截器可按如下步驟進(jìn)行:

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

    (2)通過Session啟用攔截器,或者通過Configuration啟用全局?jǐn)r截器。

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

    public class MyInterceptor extends EmptyInterceptor

    {

    ??? //更新的次數(shù)

    ??? private int updates;

    ??? //插入的次數(shù)

    ??? private int creates;

    ??? //刪除數(shù)據(jù)時,將調(diào)用onDelete方法

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

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

    ??? {

    ??????? //do nothing

    ??? }

    ??? //同步Session和數(shù)據(jù)庫中的數(shù)據(jù)

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

    ??????? }

    ??? //加載持久化實例時,調(diào)用該方法

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

    ??? }

    ??? //保存持久化實例時,調(diào)用該方法

    ??? 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("創(chuàng)建的次數(shù): " + creates + ", 更新的次數(shù): " +

    ??? updates);

    ??? }

    ??? public void preFlush(Iterator entities)

    ??? {

    ??????? updates=0;

    ??????? creates=0;

    ??? }

    ??? //事務(wù)提交前,觸發(fā)該方法

    ??? public void beforeTransactionCompletion(Transaction tx)

    ??? {

    ??????? System.out.println("事務(wù)即將結(jié)束");

    ??? }

    ??? //事務(wù)提交后,觸發(fā)該方法

    ??? public void afterTransactionCompletion(Transaction tx)

    ??? {

    ??????? System.out.println("事務(wù)已經(jīng)結(jié)束");

    ??? }

    }

    在上面的攔截器實現(xiàn)類中,實現(xiàn)了很多方法,這些方法都是在Hibernate執(zhí)行特定動作時自動調(diào)用。

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

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

    ?? ● 通過Configuration的setInterceptor(Interceptor in)方法設(shè)置全局?jǐn)r截器。

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

    public class HibernateUtil

    {

    ??? //靜態(tài)類屬性 SessionFactory

    ??? public static final SessionFactory sessionFactory;

    ??? //靜態(tài)初始化塊,完成靜態(tài)屬性的初始化

    ??? static

    ??? {

    ??????? try

    ??????? {

    ??????????? //采用默認(rèn)的hibernate.cfg.xml來啟動一個Configuration的實例

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

    ??????????? //由Configuration的實例來創(chuàng)建一個SessionFactory實例

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

    ??????? }

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

    ??????? {

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

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

    ??????? }

    ??? }

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

    ??? 對線程同步???

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

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

    ??? public static Session currentSession() throws HibernateException

    ??? {

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

    ??????? //如果該線程還沒有Session,則創(chuàng)建一個新的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,則創(chuàng)建一個新的Session

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

    ??????? {

    ??????????? //以攔截器創(chuàng)建Session對象

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

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

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

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

    ??????? return s;

    ??? }

    ??? //關(guān)閉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());

    ??? //開始事務(wù)

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

    ??? //執(zhí)行下面的代碼時,可以看到系統(tǒng)回調(diào)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);

    ??? */

    ??? //執(zhí)行下面的代碼時,可以看到系統(tǒng)回調(diào)onLoad等方法

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

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

    ??? User u = (User)o;

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

    ??? //提交事務(wù)時,可以看到系統(tǒng)回調(diào)事務(wù)相關(guān)方法

    ??? tx.commit();

    ??? HibernateUtil.closeSession();

    }

    4.8.2 事件系統(tǒng)

    Hibernate 3的事件系統(tǒng)是功能更強(qiáng)大的事件框架,事件系統(tǒng)可以替代攔截器,也可以作為攔截器的補(bǔ)充來使用。

    基本上,Session接口的每個方法都有對應(yīng)的事件。如LoadEvent和FlushEvent等。當(dāng)Session調(diào)用某個方法時,Hibernate Session會生成對應(yīng)的事件,并激活對應(yīng)的事件監(jiān)聽器。

    系統(tǒng)默認(rèn)監(jiān)聽器實現(xiàn)的處理過程,完成了所有的數(shù)據(jù)持久化操作,包括插入和修改等操作。如果用戶定義了自己的監(jiān)聽器,則意味著用戶必須完成對象的持久化操作。

    例如,可以在系統(tǒng)中實現(xiàn)并注冊LoadEventListener監(jiān)聽器,該監(jiān)聽器負(fù)責(zé)處理所有調(diào)用Session的load()方法的請求。

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

    使用事件系統(tǒng)可按如下步驟進(jìn)行:

    (1)實現(xiàn)自己的事件監(jiān)聽器類;

    (2)注冊自定義事件監(jiān)聽器,代替系統(tǒng)默認(rèn)的事件監(jiān)聽器。

    實現(xiàn)用戶的自定義監(jiān)聽器有如下3個方法:

    ?? ● 實現(xiàn)對應(yīng)的監(jiān)聽器接口,這是不可思議的,實現(xiàn)接口必須實現(xiàn)接口內(nèi)的所有方法,關(guān)鍵是必須實現(xiàn)Hibernate對應(yīng)的持久化操作,即數(shù)據(jù)庫訪問,這意味著程序員完全取代了Hibernate的底層操作。

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

    ?? ● 繼承系統(tǒng)默認(rèn)的事件監(jiān)聽器,擴(kuò)展特定方法。

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

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

    下面是用戶自定義監(jiān)聽器的示例:

    //自定義LoadListener,繼承默認(rèn)的DefaultLoadEventListener實現(xiàn)類

    public class MyLoadListener extends DefaultLoadEventListener

    {

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

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

    ??? loadType)throws HibernateException

    ??? {

    ??????? //先調(diào)用父類的onLoad方法,從而完成默認(rèn)的持久化操作

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

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

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

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

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

    ??????? return o;

    ??? }

    }

    下面還有一個MySaveListener,用于監(jiān)聽SaveEvent事件:

    //自定義SavaListener,繼承默認(rèn)的DefaultSaveEventListener實現(xiàn)類

    public class MySaveListener extends DefaultSaveEventListener

    {

    ??? //該方法完成實際的數(shù)據(jù)插入動作

    ??? protected Serializable performSaveOrUpdate(SaveOrUpdateEvent event)

    ??? {

    ??????? //先執(zhí)行用戶自定義的操作

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

    ??????? //調(diào)用父類的默認(rèn)持久化操作

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

    ??? }

    }

    注意:擴(kuò)展用戶自定義監(jiān)聽器時,別忘了在方法中調(diào)用父類的對應(yīng)方法。

    注冊用戶自定義監(jiān)聽器也有兩種方法:

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

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

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

    public class HibernateUtil2

    {

    ??? //靜態(tài)類屬性 SessionFactory

    ??? public static final SessionFactory sessionFactory;

    ??? //靜態(tài)初始化塊,完成靜態(tài)屬性的初始化

    ??? static

    ??? {

    ??????? try

    ??????? {

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

    ??????????? //注冊loadEventListener監(jiān)聽器

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

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

    ??????????? //注冊saveListener監(jiān)聽器

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

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

    ??????????? //由Configuration實例來創(chuàng)建一個SessionFactory實例

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

    ??????? }

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

    ??????? {

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

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

    ??????? }

    ??? }

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

    ??? 對線程同步

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

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

    ??? public static Session currentSession() throws HibernateException

    ??? {

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

    ??????? //如果該線程還沒有Session,則創(chuàng)建一個新的Session

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

    ??????? {

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

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

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

    ??????? }

    ??????? return s;

    ??? }

    ??? //關(guān)閉Session對象

    ??? public static void closeSession() throws HibernateException

    ??? {

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

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

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

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

    ??? }

    }

    如果不想修改代碼,也可以在配置文件中使用事件監(jiān)聽器,注冊事件監(jiān)聽器的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>

    ??????? <!—設(shè)置數(shù)據(jù)庫驅(qū)動 -->

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

    ??????? </property>

    ??????? <!-- 數(shù)據(jù)庫服務(wù)的url -->

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

    ??????? </property>

    ??????? <!-- 數(shù)據(jù)庫服務(wù)的用戶名 -->

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

    ??????? <!-- 數(shù)據(jù)庫服務(wù)的密碼 -->

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

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

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

    ??????? <!-- 設(shè)置數(shù)據(jù)庫方言 -->

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

    ??????? </property>

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

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

    ??????? <!-- 配置應(yīng)用啟動時,是否啟動自動建表 -->

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

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

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

    ??????? <!-- 注冊事件監(jiān)聽器 -->

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

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

    ??? </session-factory>

    </hibernate-configuration>

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

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

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

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


    網(wǎng)站導(dǎo)航:
     
    主站蜘蛛池模板: 亚洲AV无码一区二区二三区软件| 亚洲国产成人综合| 成人A片产无码免费视频在线观看| 亚洲欧美成人综合久久久| 日本xxwwxxww在线视频免费| 国产精品亚洲天堂| 亚洲精品自在在线观看| 猫咪免费人成网站在线观看| 亚洲av无码偷拍在线观看| 亚洲日本va中文字幕久久| 日本免费xxxx| 亚洲手机中文字幕| 亚洲国产天堂久久综合| 免费无码VA一区二区三区| 亚洲av无码成人精品区一本二本 | 韩国日本好看电影免费看| 国产精品黄页免费高清在线观看 | 免费a级毛片无码a∨免费软件| 亚洲人成网站18禁止久久影院| 亚洲日本一区二区三区在线不卡| 最近免费中文字幕mv电影| 欧亚一级毛片免费看| 亚洲欧洲日产国码一级毛片| 18成禁人视频免费网站| 春意影院午夜爽爽爽免费| 亚洲性无码av在线| 国产午夜亚洲精品午夜鲁丝片| 女人18毛片a级毛片免费| 免费h视频在线观看| 视频一区在线免费观看| 国产午夜亚洲不卡| 好爽…又高潮了毛片免费看| 久久永久免费人妻精品| 欧洲精品码一区二区三区免费看| 亚洲砖码砖专无区2023| 亚洲精品在线观看视频| 最新精品亚洲成a人在线观看| 日本一道一区二区免费看| 免费三级毛片电影片| 免费无码又爽又刺激高潮视频| kk4kk免费视频毛片|