posts - 431,  comments - 344,  trackbacks - 0
           

          在某些情況下,我們需要對實體的CURD操作進(jìn)行捕獲并執(zhí)行一些操作,這可以通過數(shù)據(jù)庫觸發(fā)器來實現(xiàn),但是正如我們上一節(jié)中所分析的,由于觸發(fā)器的執(zhí)行對Hibernate Session是透明的,因此會帶來很多問題(參見上一節(jié))。為此Hibernate提供了一些專門用于捕獲監(jiān)聽實體CURD操作的接口,通過這些接口可以實現(xiàn)類似觸發(fā)器的功能,能夠在實體發(fā)生CURD操作時捕獲事件,并且執(zhí)行相應(yīng)的動作邏輯。在Hibernate中這些接口是:Lifecycle,Validatable,Interceptor,下面我們就分別講解怎樣通過這些接口,實現(xiàn)回調(diào)攔截的技術(shù)細(xì)節(jié)。

          ALifecycleValidatable

           HibernateLifecycle接口定義如下:

          public interface Lifecycle{

           /**

             在實體對象執(zhí)行save/insert操作之前觸發(fā)

           **/

           public boolean onSave(Session session) throws CallbackException;

           /**

             session.update()執(zhí)行之前觸發(fā)

           **/

           public boolean onUpdate(Session session) throws CallbackException;

           /**

           在實體對象執(zhí)行delete操作之前觸發(fā)

          **/

          public boolean onDelete(Session session) throws CallbackException;

          /**

           在實體對象加載之后觸發(fā)

          **/

          public void onLoad(Session session) throws CallbackException;

          }

          實體對象可以實現(xiàn)Lifecycle接口,來獲得在持久化階段捕獲CURD事件,并執(zhí)行相應(yīng)動作的能如下所示:

          public class User implements Serializable,Lifecycle{

           public boolean onSave(Session s) throws CallbackException{

          ……

          return false;

          ……

           }

           public boolean onUpdate(Session s) throws CallbackException{

          ……

          return true;

          ……

           }

           public boolean onDelete(Session s) throws CallbackException{

          ……

          return false;

          ……

           }

           public boolean onLoad(Session s) throws CallbackException{

          ……

           }

          }

          對于onSave,onUpdate,onDelete方法,如果返回true則意味著需要終止執(zhí)行對應(yīng)的操作過程。如果在運行時拋出CallbackException,對應(yīng)的操作也會被終止。

          注意在接口中對應(yīng)的方法中,不要去通過方法的Session參數(shù)執(zhí)行持久化操作,在這些方法中Session無法正常使用,如果必須要執(zhí)行一些持久化操作,那么需要進(jìn)行特殊的處理,我們將在Interceptor部分詳細(xì)講解。

          Hibernate中還定義了Validatable接口,該接口定義如下:

          public interface Validatable{

           public void validate() throws ValidationFailure;

          }

          Validatable接口是用來實現(xiàn)數(shù)據(jù)驗證的,實體類實現(xiàn)Validatable接口,并在接口的validate方法中實現(xiàn)數(shù)據(jù)驗證邏輯,以保證數(shù)據(jù)輸入的合法性。validate方法將會在實體對象持久化前得到調(diào)用進(jìn)行數(shù)據(jù)驗證,與Lifecycle接口中的方法不同,Validatable.validate()方法在實體生命周期中可能被多次調(diào)用,因此此方法應(yīng)該僅限于數(shù)據(jù)合法性的驗證,而不應(yīng)該實現(xiàn)業(yè)務(wù)邏輯的驗證。

          BInterceptor:

          以上是Hibernate提供的Lifecycle接口和Validatable接口,以及使用方法,這兩個方法定義了一種自然的回調(diào)機(jī)制,但是如我們所見,如果想實現(xiàn)對實體的回調(diào)攔截,那么相應(yīng)的實體對象必須實現(xiàn)這兩個Hibernate原生接口,這就使代碼的可移植性大大下降,因為此時實體類已經(jīng)不再是一個POJO了,Hibernate的那些天才的設(shè)計者們也已經(jīng)意識到了這個問題,所以又提供了Interceptor接口,為持久化事件的捕獲和處理提供了一個非入侵性的解決方案,Interceptor接口通過設(shè)置注入來實現(xiàn)持久化事件的捕獲和處理,這是典型的IOC(控制反轉(zhuǎn))設(shè)計思想。下面我們就講解Interceptor接口的技術(shù)細(xì)節(jié)和使用方法。

          Hibernate中的Interceptor接口定義如下:

          public interface Interceptor{

           //對象初始化之前調(diào)用,這時實體對象剛剛被創(chuàng)建,各個屬性還都為null,如果在這個方法中修改了實體對象的數(shù)據(jù),那么返回true,否則返回null.

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

          String[] propertyNames,Type[] types) throws CallbackException;

                //Session.flush()在進(jìn)行臟數(shù)據(jù)檢查時,如果發(fā)現(xiàn)實體對象數(shù)據(jù)已臟,就調(diào)用此方法

           public boolean onFlushDirty(Object entity,Serializable id,Object[] state,

          String[] propertyNames,Type[] types) throws CallbackException;

           //實體對象被保存前調(diào)用,如果在這個方法中修改了實體對象的數(shù)據(jù),那么返回true,否則返回null.

           public boolean onSave(Object entity,Serializable id,Object[] state,

          String[] propertyNames,Type[] types) throws CallbackException;

               //通過Session刪除一個實體對象前調(diào)用

           public boolean onDelete(Object entity,Serializable id,Object[] state,

          String[] propertyNames,Type[] types) throws CallbackException;

               //Session執(zhí)行flush()之前調(diào)用

          public boolean preFlush(Iterator entities) throws CallbackException;

               //Session執(zhí)行flush()之后,所有的SQL語句都執(zhí)行完畢后調(diào)用

          public boolean postFlush(Iterator entities) throws CallbackException;

               //當(dāng)執(zhí)行saveOrUpdate方法時調(diào)用,判斷實體對象是否已經(jīng)保存

               public Boolean isUnsaved(Object entity);

               //執(zhí)行Session.flush()方法時,調(diào)用此方法判斷該對象是否為臟對象,這提供了臟數(shù)據(jù)檢查的另一個回調(diào)攔截機(jī)制

          public int[] findDirty(Object entity,Serializable id,Object[] state,

          String[] propertyNames,Type[] types) throws CallbackException;

               //當(dāng)Session構(gòu)造實體類實例前調(diào)用,如果返回null,Hibernate會按照默認(rèn)方式構(gòu)造實體類對象實例

          public Object findDirty(Class clazz,Serializable id) throws CallbackException;

          }

          Intercepter不需要實體對象來實現(xiàn),而是通過開發(fā)人員定義一個實現(xiàn)Interceptor接口的類,然后在創(chuàng)建Hibernate Session時,通過將Interceptor對象設(shè)置進(jìn)所創(chuàng)建的Session,這樣通過這個Session來操作的實體對象,就都會具有對持久化動作的回調(diào)攔截能力。在HibernateInterceptor對象共有兩種用法,如下所述:

          1                SessionFactory.openSession(Interceptor):為每個Session實例分配一個攔截Interceptor,這個攔截接口對象,存放在Session范圍內(nèi),為每個Session實例所專用。

          2                Configuration.setInterceptor(Interceptor):SessionFactory實例分配一個Interceptor實例,這個Interceptor實例存放在SessionFactory范圍內(nèi),被每個Session實例所共享。

          AInterceptor的典型應(yīng)用:

          下面我實現(xiàn)一個利用Interceptor接口實現(xiàn)日志數(shù)據(jù)稽核的功能,所謂日志數(shù)據(jù)稽核就是針對一些關(guān)鍵操作進(jìn)行記錄,以便作為業(yè)務(wù)跟蹤的基礎(chǔ)依據(jù)。

          首先定義用于記錄操作的實體:

          public class AudiLog implements Serializable{

           private String id;

           private String user;

           private String action;

           private String entityName;

           private String comment;

           private Long logtime;

           …getter/setter…

          }

          接下來定義Interceptor接口的實現(xiàn)類和用于持久化操作的AuditDAO類:

          package com.lbs.apps.unemployment.subsidy.beforeinfoimport.util;

          import net.sf.hibernate.Session;

          import net.sf.hibernate.Interceptor;

          import Java.io.Serializable;

          import net.sf.hibernate.type.Type;

          import net.sf.hibernate.HibernateException;

          import Java.util.Iterator;

          import Java.util.Set;

          import Java.util.HashSet;

          import com.neusoft.entity.User;

          public class MyInterceptor implements Interceptor{

           private Set insertset=new HashSet();

           private Set updateset=new HashSet();

           private Session session;

           private String userID;

           public void setSession(Session session){

              this.session=session

           }

           public void setUserID(String id){

             this.userID=id;

           }

           public boolean onLoad(Object object, Serializable serializable,

                                  Object[] objectArray, String[] stringArray,

                                  Type[] typeArray) {

              return false;

           }

           public boolean onFlushDirty(Object object, Serializable serializable,

                                        Object[] objectArray, Object[] objectArray3,

                                        String[] stringArray, Type[] typeArray) {

              if(object instanceof User){

                insertset.add(object);

              }

              return false;

           }

           public boolean onSave(Object object, Serializable serializable,

                                  Object[] objectArray, String[] stringArray,

                                  Type[] typeArray) {

              if(object instanceof User){

                updateset.add(object);

              }

              return false;

           }

           public void onDelete(Object object, Serializable serializable,

                                 Object[] objectArray, String[] stringArray,

                                 Type[] typeArray) {

           }

           public void preFlush(Iterator iterator) {

           }

           public void postFlush(Iterator iterator) {

          try{

           if(insertset.size()>0){

             AuditDAO.dolog(“insert”,userID,inserset,session.connection);

           }

           if(updateset.size()>0){

             AuditDAO.dolog(“update”,userID,updateset,session.connection);

           }

          }catch(HibernateException he){

           he.printStackTrace();

          }

           }

           public Boolean isUnsaved(Object object) {

              return null;

           }

           public int[] findDirty(Object object, Serializable serializable,

                                   Object[] objectArray, Object[] objectArray3,

                                   String[] stringArray, Type[] typeArray) {

              return null;

           }

           public Object instantiate(Class class0, Serializable serializable) {

              return "";

           }

          }

          public class AuditDAO{

           public static void doLog(String action,String userID,Set modifySet,Connection connection){

               Session tempsession=HibernateUtil.getSessionFactory().openSession(connection);

               try{

                 Iterator it=modifyset.iterator();

                 while(it.hasNext()){

                   User user=(User)it.next();

                   AudiLog log=new AudiLog();

                   log.setUserID(userID);

                   log.setAction(action);

                   log.setComment(user.toString());

                   log.setLogTime(new Long(Calendar.getInstance().getTime().getTime()));

                   tempsession.save(log);

                 }

               }catch(Exception e){

                 throw new CallbackException(e);

               }finally{

                 try{

                   tempsesson.close();

                 }catch(HibernateException he){

                   throw new CallbackException(he);

                 }

               }

           }

          }

          最后看一下業(yè)務(wù)邏輯主程序:

          SessionFactory sessionfactory=config.buildSessionFactory();

          MyInterceptor it=new MyInterceptor();

          session=sessionfactory().openSession(it);

          it.setUserID(“currentUser”);

          it.setSession(session);

          User user=new User();

          user.setName(“zx”);

          Transaction tx=session.beginTransaction();

          session.save(user);

          tx.commit();

          session.close();

          以上示例代碼中,在創(chuàng)建Session時,設(shè)置Interceptor實例對象,當(dāng)執(zhí)行到session.save(user)前,會觸發(fā)onSave()方法,當(dāng)執(zhí)行tx.commit()時,會執(zhí)行flush(),在執(zhí)行該方法后會觸發(fā)postFlush()方法,這個方法通過AuditDAO進(jìn)行持久化保存業(yè)務(wù)日志,在這個類中的紅色部分時有關(guān)持久化操作部分,我們并沒有使用原有的Session實例,這是因為要避免Session內(nèi)部狀態(tài)混亂,因此我們依托當(dāng)前SessionJDBC Connection創(chuàng)建了一個臨時Session用于保存操作記錄,在這個持久化操作中沒有啟動事務(wù),這是因為臨時Session中的JDBC Connection是與外圍調(diào)用InterceptorSession共享,而事務(wù)已經(jīng)在外圍SessionJDBC Connection上啟動。這是在攔截方法中進(jìn)行持久化操作的標(biāo)準(zhǔn)方法。總之Interceptor提供了非入侵性的回調(diào)攔截機(jī)制,使我們可以方便而且優(yōu)雅的實現(xiàn)一些持久化操作的特殊需求。
          posted on 2009-06-11 16:49 周銳 閱讀(530) 評論(0)  編輯  收藏 所屬分類: Hibernate
          主站蜘蛛池模板: 榆树市| 繁昌县| 嘉鱼县| 绥芬河市| 乡宁县| 韩城市| 东平县| 丹棱县| 舒兰市| 新野县| 威远县| 陆良县| 台山市| 庄浪县| 吉木萨尔县| 四会市| 克拉玛依市| 宝丰县| 屏南县| 油尖旺区| 兰坪| 大埔县| 平和县| 松桃| 上蔡县| 乐平市| 宽甸| 壤塘县| 太原市| 老河口市| 卢湾区| 沙坪坝区| 通化县| 卢氏县| 通江县| 五峰| 贡嘎县| 格尔木市| 英超| 丰台区| 西乡县|