日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

Hibernate的事件机制

發(fā)布時(shí)間:2023/12/10 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Hibernate的事件机制 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

4.8 事 件 機(jī) 制

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

通過(guò)事件框架,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)聽(tīng)器。

4.8.1 攔截器

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

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

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

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

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

下面是一個(gè)攔截器的示例代碼,該攔截器沒(méi)有進(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ù)庫(kù)中的數(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)于攔截器的使用。攔截器的使用有兩種方法:

?? ● 通過(guò)SessionFactory的openSession(Interceptor in)方法打開(kāi)一個(gè)帶局部攔截器的Session。

?? ● 通過(guò)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來(lái)啟動(dòng)一個(gè)Configuration的實(shí)例

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

??????????? //由Configuration的實(shí)例來(lái)創(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();

??? //不加攔截器的打開(kāi)Session方法

??? public static Session currentSession() throws HibernateException

??? {

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

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

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

??????? {

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

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

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

??????? }

??????? return s;

??? }

??? //加攔截器的打開(kāi)Session方法

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

??? HibernateException

??? {

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

??????? //如果該線程還沒(méi)有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()

{

??? //以攔截器開(kāi)始Session

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

??? //開(kāi)始事務(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("中國(guó)");

??? 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ǔ)充來(lái)使用。

基本上,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)器。

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

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

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

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

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

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

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

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

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

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

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

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

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

//自定義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)聽(tīng)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)聽(tīng)器時(shí),別忘了在方法中調(diào)用父類的對(duì)應(yīng)方法。

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

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

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

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

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)聽(tīng)器

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

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

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

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

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

??????????? //由Configuration實(shí)例來(lái)創(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();

??? //不加攔截器的打開(kāi)Session方法

??? public static Session currentSession() throws HibernateException

??? {

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

??????? //如果該線程還沒(méi)有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)聽(tīng)器,注冊(cè)事件監(jiān)聽(tīng)器的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ù)庫(kù)驅(qū)動(dòng) -->

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

??????? </property>

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

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

??????? </property>

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

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

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

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

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

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

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

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

??????? </property>

??????? <!-- 顯示Hibernate生成的SQL語(yǔ)句 -->

??????? <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)聽(tīng)器 -->

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

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

??? </session-factory>

</hibernate-configuration>

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

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

轉(zhuǎn)載于:https://www.cnblogs.com/jadmin/archive/2009/07/19/2206094.html

總結(jié)

以上是生活随笔為你收集整理的Hibernate的事件机制的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。