自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

詳解Hibernate攔截器與事件監(jiān)聽器

開發(fā) 后端
Hibernate 為我們提供了實現(xiàn)攔截器的接口org.hibernate.Interceptor,它里面提供了許多攔截事件。通常不需要實現(xiàn)這個接口,因為我們實現(xiàn)自己的攔截器不可能每一個事件都是必須的。

攔截器(Intercept):與Struts2的攔截器機制基本一樣,都是一個操作穿過一層層攔截器,每穿過一個攔截器就會觸發(fā)相應(yīng)攔截器的事件做預(yù)處理或善后處理。

監(jiān)聽器(Listener):其實功能與攔截器是相似的,但它實現(xiàn)原理不同,它是為每一個事件注冊一個或多個監(jiān)聽器,一旦事件發(fā)生,則事件源通知所有監(jiān)聽該事件的監(jiān)聽器,然后監(jiān)聽器處理通知(觀察者模式)。

攔截器

Hibernate 為我們提供了實現(xiàn)攔截器的接口org.hibernate.Interceptor,它里面提供了許多攔截事件。通常不需要實現(xiàn)這個接口,因為我們實現(xiàn)自己的攔截器不可能每一個事件都是必須的。所以Hibernate為我們提供了org.hibernate.Interceptor接口的一個空實現(xiàn)類 org.hibernate.EmptyIntercept,通常情況下我們只需繼承這個空實現(xiàn)類,Override需要的事件方法即可。

攔截器的工作原理簡易示意圖:

設(shè)置攔截器后,相應(yīng)的操作都會先穿過一層層相應(yīng)的攔截器,讓攔截器執(zhí)行預(yù)處理或善后處理。

攔截器使用實例:

創(chuàng)建攔截器:

  1. public class AutoUpdateTimeInterceptor extends EmptyInterceptor  
  2. {  
  3.     private static final long serialVersionUID = -8597658125309889388L;  
  4.       
  5.     /*  
  6.      * entity - POJO對象  
  7.      * id - POJO對象的主鍵  
  8.      * state - POJO對象的每一個屬性所組成的集合(除了ID)  
  9.      * propertyNames - POJO對象的每一個屬性名字組成的集合(除了ID)  
  10.      * types - POJO對象的每一個屬性類型所對應(yīng)的Hibernate類型組成的集合(除了ID)  
  11.      */ 
  12.     @Override 
  13.     public boolean onSave(Object entity, Serializable id, Object[] state,  
  14.             String[] propertyNames, Type[] types)  
  15.     {      
  16.         if (entity instanceof People)  
  17.         {  
  18.             for (int index=0;index<propertyNames.length;index++)  
  19.             {  
  20.                 /*找到名為"checkinTime"的屬性*/ 
  21.                 if ("checkinTime".equals(propertyNames[index]))  
  22.                 {  
  23.                     /*使用攔截器將People對象的"checkinTime"屬性賦上值*/ 
  24.                     state[index] = new Timestamp(new Date().getTime());  
  25.                     return true;  
  26.                 }  
  27.             }  
  28.         }  
  29.  
  30.         return false;  
  31.     }  
  32. }  

場景類

  1. public class Client  
  2. {  
  3.     public static void main(String[] args)  
  4.     {  
  5.         /*為Session添加攔截器*/ 
  6.         Session session = HibernateUtil.getSessionFactory().openSession(new AutoUpdateTimeInterceptor());  
  7.         Transaction tx = null;  
  8.         try 
  9.         {  
  10.             tx = session.beginTransaction();  
  11.               
  12.             People people = new People();  
  13.             people.setName("zhangsan");  
  14.               
  15.             session.save(people);  
  16.               
  17.             tx.commit();  
  18.         }  
  19.         catch (Exception e)  
  20.         {  
  21.             if(tx!=null)  
  22.             {  
  23.                 tx.rollback();  
  24.             }  
  25.               
  26.             e.printStackTrace();  
  27.         }  
  28.         finally 
  29.         {  
  30.             session.close();  
  31.         }  
  32.     }  

場景類中并沒有顯示的設(shè)置了people對象的"checkinTime"的屬性值,啟動該場景類代碼,現(xiàn)在來查看數(shù)據(jù)庫信息:

可以看到checkin_time這列屬性依然被賦值了,說明該賦值操作是攔截器幫助我們完成的。使用攔截器的時候需要注意攔截器的返回值,我以前一直以為攔截器的返回值會控制一個操作是否可以繼續(xù),通過實驗發(fā)現(xiàn),即使返回false操作也會繼續(xù)執(zhí)行的,只是返回false的話,攔截器的所有設(shè)置都是無效的,不會反應(yīng)到數(shù)據(jù)庫中。

返回false:

  1. public class AutoUpdateTimeInterceptor extends EmptyInterceptor  
  2. {  
  3.     private static final long serialVersionUID = -8597658125309889388L;  
  4.       
  5.     /*  
  6.      * entity - POJO對象  
  7.      * id - POJO對象的主鍵  
  8.      * state - POJO對象的每一個屬性所組成的集合(除了ID)  
  9.      * propertyNames - POJO對象的每一個屬性名字組成的集合(除了ID)  
  10.      * types - POJO對象的每一個屬性類型所對應(yīng)的Hibernate類型組成的集合(除了ID)  
  11.      */ 
  12.     @Override 
  13.     public boolean onSave(Object entity, Serializable id, Object[] state,  
  14.             String[] propertyNames, Type[] types)  
  15.     {      
  16.         if (entity instanceof People)  
  17.         {  
  18.             for (int index=0;index<propertyNames.length;index++)  
  19.             {  
  20.                 /*找到名為"checkinTime"的屬性*/ 
  21.                 if ("checkinTime".equals(propertyNames[index]))  
  22.                 {  
  23.                     /*使用攔截器將People對象的"checkinTime"屬性賦上值*/ 
  24.                     state[index] = new Timestamp(new Date().getTime());  
  25. //                  return true;  
  26.                 }  
  27.             }  
  28.         }  
  29.  
  30.         return false;  
  31.     }  

查看插入的數(shù)據(jù):

可以看到數(shù)據(jù)依然保存到數(shù)據(jù)庫中了,但攔截器的操作并沒有反映到數(shù)據(jù)庫中,攔截器的操作是無效的。

但是比較奇怪的是Console輸出的SQL語句:

  1. Hibernate:   
  2.     insert   
  3.     into  
  4.         people  
  5.         (name, checkin_time, id)   
  6.     values  
  7.         (?, ?, ?)  
  8. Hibernate:   
  9.     update  
  10.         people   
  11.     set  
  12.         name=?,  
  13.         checkin_time=?   
  14.     where  
  15.         id=? 

居然多了一條Update語句,我使用了p6spy顯示了這兩條SQL語句的綁定值:

  1. 1327304507491|0|0|statement|insert into people (name, checkin_time, id) values (?, ?, ?)|insert into people (name, checkin_time, id) values ('zhangsan''2012-01-23 15:41:47.45''402881e53509837f0135098380370001')  
  2. 1327304507491|0|0|statement|update people set name=?, checkin_time=? where id=?|update people set name='zhangsan', checkin_time='' where id='402881e53509837f0135098380370001' 

可以看到,攔截器的操作會直接反映到數(shù)據(jù)庫中的,但是如果返回值是false的話,Hibernate會產(chǎn)生一條Update SQL語句將攔截器的操作結(jié)果取消了。

最后,Hibernate的攔截器有兩種設(shè)置方式,一種是使用sessionFactory.openSession(Interceptor interceptor),這樣的攔截器只會針對該session有效,又叫做局部攔截器。另一種是使用Configuration的setInterceptor(Interceptor interceptor)方法設(shè)置,這樣的攔截器對每一個session都有效,又稱之為全局攔截器。

事件監(jiān)聽器

基本上,Session接口的每個方法都有相對應(yīng)的事件。比如 LoadEvent,F(xiàn)lushEvent,等等(查閱XML配置文件的DTD,以及org.hibernate.event包來獲得所有已定義的事件的列表)。當某個方法被調(diào)用時,Hibernate Session會生成一個相對應(yīng)的事件并激活所有配置好的事件監(jiān)聽器。系統(tǒng)預(yù)設(shè)的監(jiān)聽器實現(xiàn)的處理過程就是被監(jiān)聽的方法要做的(被監(jiān)聽的方法所做的其實僅僅是激活監(jiān)聽器, “實際”的工作是由監(jiān)聽器完成的)。不過,你可以自由地選擇實現(xiàn)一個自己定制的監(jiān)聽器(比如,實現(xiàn)并注冊用來處理處理LoadEvent的 LoadEventListener接口), 來負責(zé)處理所有的調(diào)用Session的load()方法的請求。

在定義自己的事件監(jiān)聽器時,其實不需要實現(xiàn)XXXListener接口,Hibernate為了方便我們定義事件監(jiān)聽器,已經(jīng)為每個事件監(jiān)聽器接口實提供了一個默認的實現(xiàn)。在org.hibernate.event.def包下面可以找到Hibernate為我們提供的默認實現(xiàn),我們只需要繼承這些默認實現(xiàn),在其基礎(chǔ)上添加我們自定義的功能即可。

事件監(jiān)聽器的簡單示意圖:

 

當某個方法被調(diào)用時,Hibernate Session會生成一個相對應(yīng)的事件并激活所有配置好的事件監(jiān)聽器。

事件監(jiān)聽器使用:

創(chuàng)建事件監(jiān)聽器:

  1. public class SaveOrUpdateListener extends DefaultSaveOrUpdateEventListener  
  2. {  
  3.     private static final long serialVersionUID = 7496518453770213930L;  
  4.  
  5.     /*監(jiān)聽保存或更新事件*/ 
  6.     @Override 
  7.     public void onSaveOrUpdate(SaveOrUpdateEvent event)  
  8.     {  
  9.         People people = null;  
  10.           
  11.         if(event.getObject() instanceof People)  
  12.         {  
  13.             people = (People)event.getObject();  
  14.         }  
  15.           
  16.         people.setCheckinTime(new Timestamp(new Date().getTime()));  
  17.           
  18.         System.out.println("invoke!");  
  19.           
  20.         /*一定要調(diào)用父類提供的功能,不然就和繼承接口一樣了*/ 
  21.         super.onSaveOrUpdate(event);  
  22.     }  

通過hibernate.cfg.xml配置文件將事件監(jiān)聽器配置到Hibernate中:

第一種配置方式:

  1. <event type="save-update"> 
  2.     <listener class="com.suxiaolei.hibernate.listener.SaveOrUpdateListener"/> 
  3. </event> 

第二種配置方式:

  1. <listener class="com.suxiaolei.hibernate.listener.SaveOrUpdateListener" type="save-update"/> 

兩種配置方式產(chǎn)生的效果都是一樣的。只是一個以"事件"為主,一個以"監(jiān)聽器"為主。type是指定監(jiān)聽事件的類型,class指定監(jiān)聽器的實現(xiàn)類,一個事件可以有多個監(jiān)聽器。type有許多取值,下表列出了所有type的值:

上面列表每一個選項對應(yīng)著一個特定的事件。

場景類:

  1. public class Client  
  2. {  
  3.     public static void main(String[] args)  
  4.     {  
  5.         Session session = HibernateUtil.getSessionFactory().openSession();  
  6.         Transaction tx = null;  
  7.         try 
  8.         {  
  9.             tx = session.beginTransaction();  
  10.               
  11.             People people = new People();  
  12.             people.setName("lisi");  
  13.               
  14.             session.saveOrUpdate(people);  
  15.               
  16.             tx.commit();  
  17.         }  
  18.         catch (Exception e)  
  19.         {  
  20.             if(tx!=null)  
  21.             {  
  22.                 tx.rollback();  
  23.             }  
  24.               
  25.             e.printStackTrace();  
  26.         }  
  27.         finally 
  28.         {  
  29.             session.close();  
  30.         }  
  31.     }  

people對象依然沒有設(shè)置checkinTime屬性,運行程序后,查看數(shù)據(jù)庫:

可以看到,checkin_time字段的依然賦值了,說明我們配置的事件監(jiān)聽器生效了。

使用事件監(jiān)聽器我發(fā)現(xiàn)需要注意父類行為的順序,例如:

  1. public void onSaveOrUpdate(SaveOrUpdateEvent event)  
  2. {  
  3.         People people = null;  
  4.           
  5.         if(event.getObject() instanceof People)  
  6.         {  
  7.             people = (People)event.getObject();  
  8.         }  
  9.           
  10.         people.setCheckinTime(new Timestamp(new Date().getTime()));  
  11.           
  12.         System.out.println("invoke!");  
  13.           
  14.         /*一定要調(diào)用父類提供的功能,不然就和繼承接口一樣了*/ 
  15.         super.onSaveOrUpdate(event);  
  1. public void onSaveOrUpdate(SaveOrUpdateEvent event)  
  2. {  
  3.         /*一定要調(diào)用父類提供的功能,不然就和繼承接口一樣了*/ 
  4.         super.onSaveOrUpdate(event);  
  5.           
  6.         People people = null;  
  7.           
  8.         if(event.getObject() instanceof People)  
  9.         {  
  10.             people = (People)event.getObject();  
  11.         }  
  12.           
  13.         people.setCheckinTime(new Timestamp(new Date().getTime()));  
  14.           
  15.         System.out.println("invoke!");  

例如上面的順序,雖然最后產(chǎn)生的效果一致,但是第二種順序會多產(chǎn)生一條update語句,有可能會產(chǎn)生性能問題,所以在使用事件監(jiān)聽器的時候需要多加注意。

原文鏈接:http://www.cnblogs.com/otomedaybreak/archive/2012/01/23/2328980.html

【編輯推薦】

  1. Hibernate的緩存解讀
  2. Hibernate的集合映射
  3. Hibernate關(guān)聯(lián)關(guān)系配置
  4. Hibernate復(fù)合主鍵映射
  5. Hibernate繼承映射
責(zé)任編輯:林師授 來源: 音①曉的博客
相關(guān)推薦

2011-05-16 10:14:11

Hibernate

2009-09-27 17:46:22

Hibernate監(jiān)聽

2009-09-27 17:37:32

Hibernate攔截

2025-02-28 08:14:53

2023-11-01 07:55:03

事件監(jiān)聽器傳遞數(shù)據(jù)

2010-08-09 11:06:01

Flex事件機制

2009-01-03 13:37:26

Oracle監(jiān)聽器Oracle服務(wù)器Oracle網(wǎng)絡(luò)配置

2010-08-09 09:47:34

Flex事件機制

2009-07-08 17:39:23

Servlet監(jiān)聽器

2020-12-15 10:46:29

事件監(jiān)聽器Spring Boot

2011-03-21 16:21:49

Oracle監(jiān)聽口令監(jiān)聽器

2009-06-22 09:23:18

事件監(jiān)聽器

2009-07-17 09:55:02

事件監(jiān)聽器SWT和SwingAWT

2009-06-24 16:00:00

2020-04-20 11:09:49

過濾器監(jiān)聽器 Web

2021-07-08 07:52:49

容器監(jiān)聽器Event

2023-09-05 08:58:07

2011-11-21 14:21:26

SpringMVCJava框架

2009-11-09 10:03:09

WCF通道監(jiān)聽器

2010-02-22 15:06:31

WCF信道監(jiān)聽器
點贊
收藏

51CTO技術(shù)棧公眾號