<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ù)持久化操作,對(duì)用戶都是透明的,用戶無法插入自己的動(dòng)作。

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

    Hibernate的事件框架由兩個(gè)部分組成:

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

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

    4.8.1 攔截器

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

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

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

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

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

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

    public class MyInterceptor extends EmptyInterceptor

    {

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

    ??? private int updates;

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

    ??? private int creates;

    ??? //刪除數(shù)據(jù)時(shí),將調(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;

    ??????? }

    ??? //加載持久化實(shí)例時(shí),調(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;

    ??? }

    ??? //保存持久化實(shí)例時(shí),調(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é)束");

    ??? }

    }

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

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

    ?? ● 通過SessionFactory的openSession(Interceptor in)方法打開一個(gè)帶局部攔截器的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來啟動(dòng)一個(gè)Configuration的實(shí)例

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

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

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

    ??????? }

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

    ??????? {

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

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

    ??????? }

    ??? }

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

    ??? 對(duì)線程同步???

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

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

    ??? public static Session currentSession() throws HibernateException

    ??? {

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

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

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

    ??????? {

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

    ??????????? //將獲得的Session變量存儲(chǔ)在ThreadLocal變量的Session里

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

    ??????? }

    ??????? return s;

    ??? }

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

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

    ??? HibernateException

    ??? {

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

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

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

    ??????? {

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

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

    ??????????? //將獲得的Session變量存儲(chǔ)在ThreadLocal變量的Session里

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

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

    ??????? return s;

    ??? }

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

    ??? public static void closeSession() throws HibernateException

    ??? {

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

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

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

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

    ??? }

    }

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

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

    private void testUser()

    {

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

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

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

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

    ??? //執(zhí)行下面的代碼時(shí),可以看到系統(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í)行下面的代碼時(shí),可以看到系統(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ù)時(shí),可以看到系統(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接口的每個(gè)方法都有對(duì)應(yīng)的事件。如LoadEvent和FlushEvent等。當(dāng)Session調(diào)用某個(gè)方法時(shí),Hibernate Session會(huì)生成對(duì)應(yīng)的事件,并激活對(duì)應(yīng)的事件監(jiān)聽器。

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    public class MyLoadListener extends DefaultLoadEventListener

    {

    ??? //在LoadEventListener接口僅僅定義了這個(gè)方法

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

    ??? }

    }

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

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

    public class MySaveListener extends DefaultSaveEventListener

    {

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

    ??? protected Serializable performSaveOrUpdate(SaveOrUpdateEvent event)

    ??? {

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

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

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

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

    ??? }

    }

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

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

    ?? ● 編程式,通過使用Configuration對(duì)象編程注冊(cè)。

    ?? ● 聲明式,在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();

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

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

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

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

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

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

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

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

    ??????? }

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

    ??????? {

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

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

    ??????? }

    ??? }

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

    ??? 對(duì)線程同步

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

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

    ??? public static Session currentSession() throws HibernateException

    ??? {

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

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

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

    ??????? {

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

    ??? ??????? //將獲得的Session變量存儲(chǔ)在ThreadLocal變量的Session里

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

    ??????? }

    ??????? return s;

    ??? }

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

    ??? public static void closeSession() throws HibernateException

    ??? {

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

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

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

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

    ??? }

    }

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

    ??????? <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)用啟動(dòng)時(shí),是否啟動(dòng)自動(dòng)建表 -->

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

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

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

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

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

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

    ??? </session-factory>

    </hibernate-configuration>

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

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

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

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


    網(wǎng)站導(dǎo)航:
     
    主站蜘蛛池模板: 国内精品免费麻豆网站91麻豆 | 国产精品久久久久久亚洲影视| 国产gav成人免费播放视频| 日韩电影免费在线观看网站| 亚洲欧洲春色校园另类小说| 又黄又爽的视频免费看| 国产高清不卡免费视频| 精品国产日韩亚洲一区91| 亚洲国产精品无码专区| 免费鲁丝片一级观看| 91在线视频免费观看| 亚洲人成网站在线观看播放青青| 亚洲国产精品毛片av不卡在线| 美女视频黄a视频全免费网站色窝| 色偷偷女男人的天堂亚洲网| 亚洲国产精品无码AAA片| 在线免费观看污网站| 午夜免费福利视频| 四虎影视永久在线精品免费| 久久夜色精品国产噜噜亚洲AV| 亚洲国产香蕉人人爽成AV片久久 | 伊人久久免费视频| 免费无码又爽又黄又刺激网站| 亚洲第一成年人网站| 久久99国产亚洲高清观看首页| 国产无遮挡又黄又爽免费视频| 最好看最新的中文字幕免费| 一区二区三区免费在线视频 | 日韩中文字幕精品免费一区| 两个人的视频www免费| 国产亚洲精品第一综合| 亚洲乱码一区av春药高潮| 亚洲va中文字幕无码久久| 亚洲Av无码乱码在线znlu| 无人影院手机版在线观看免费 | 在线免费一区二区| 30岁的女人韩剧免费观看| 久久久免费精品re6| 亚洲一卡2卡4卡5卡6卡在线99 | 又粗又大又硬又爽的免费视频 | 亚洲精品在线播放|