国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > Java > 正文

詳解Java的Hibernate框架中的Interceptor和Collection

2019-11-26 14:42:19
字體:
來源:轉載
供稿:網友

Interceptor
講到Interceptor,相信熟悉struts2的童鞋肯定不會陌生了,struts2可以自定義攔截器進行自己想要的一系列相關的工作。而這里我們說的Interceptor也是差不多相似的功能。
 廢話不說,直接來代碼:
 下面這個是MyInterceptor類,它實現了Interceptor接口:

public String onPrepareStatement(String arg0) {   return arg0; }  public boolean onSave(Object arg0, Serializable arg1, Object[] arg2,     String[] arg3, Type[] arg4) throws CallbackException {   if (arg0 instanceof User) {     System.out.println("User to be saved=>"+((User)arg0).getName());   }   return false; } 

其他方法就不看了,按默認實現就行,我們只需要改這兩個方法,需要把onPrepareStatement中的返回值改一下,改成返回當前的SQL語句,參數中就是傳入的執行的SQL語句,我們直接返回就可以打印出該語句。
 而在onSave中,看名字就可以知道是在保存的時候進行調用的。我們可以進行一系列保存前的工作。
 相信大家看參數名稱就可以看明白了吧。
 Serializable是指序列號的參數,在這里是指跟數據庫ID進行映射的屬性
 Object[]這是一系列的狀態,暫時沒怎么用到,以后用到再研究,但API中說明了,不管用何種方式修改了這個數組中的值,這個onSave方法必須返回true。
 String[]是指屬性的名稱
 而Type[]也就是相應屬性的類型。
 
 1)這個Interceptor可以在保存數據庫前和后做一些相應的操作。比如想對數據進行修改,添加前綴或后綴的,都可以用它來實現,下面我們來看一下。

public boolean onSave(Object arg0, Serializable arg1, Object[] arg2,     String[] arg3, Type[] arg4) throws CallbackException {   if (arg0 instanceof User) {     System.out.println("User to be saved=>"+((User)arg0).getName());   }   //我們在這里添加123作為名字的前綴   User user = (User)arg0;   user.setName("123"+user.getName());   return false; } 

我們看一下測試方法:

public static void main(String[] args) {    Configuration cfg = new Configuration().configure();   SessionFactory sessionFactory = cfg.buildSessionFactory();   Interceptor interceptor = new MyInteceptor();   Session session = sessionFactory.openSession(interceptor);        User user = new User();   user.setName("shun");        Transaction tx = session.beginTransaction();   session.save(user);        tx.commit();   session.close();      } 

很簡單,我們只是進行了簡單的保存而已。這里就沒給出映射文件和實體類,大家隨便弄個試一下就行。
 運行它,我們可以看到:

User to be saved=>shun Hibernate: insert into USER (USER_NAME, age) values (?, ?) Hibernate: update USER set USER_NAME=?, age=? where USER_ID=? 
  它會在最后進行更新姓名和年齡的操作,主要是因為我們在onSave方法中進行了修改。
201613141819453.png (976×23)
我們看到數據庫中的值已經修改為有123前綴的了。
 
 2)同樣道理,我們可以在加載時修改屬性的值:
public boolean onLoad(Object arg0, Serializable arg1, Object[] arg2,     String[] arg3, Type[] arg4) throws CallbackException {        if (arg0 instanceof User) {     System.out.println("User to be loaded=>"+(arg2[0]+":"+arg2[1]));   }   User user = (User)arg0;   //判斷哪個屬性是name   for (int i = 0; i < arg3.length; i ++){     if (arg3[i].equals("name")){       user.setName(((String)arg2[i]).replace("123",""));       arg2[i] = ((String)arg2[i]).replace("123","");     }   }   return false; } 

加載時修改屬性的值是寫在onLoad方法內。
 這里的arg0就是我們的User對象,這里它還沒有值,這個方法在load方法之后才進行調用,所以我們此時對user進行操作已經是于事無補了,而且我們這里的user.setName是沒用的操作。主要在:

arg2[i] = ((String)arg2[i]).replace("123","");

  
   這句代碼改變了返回的屬性的值,那么我們在程序中拿到的user對象中的值也會改變,我們運行測試方法看看:

public static void main(String[] args) {    Configuration cfg = new Configuration().configure();   SessionFactory sessionFactory = cfg.buildSessionFactory();   Interceptor interceptor = new MyInteceptor();   Session session = sessionFactory.openSession(interceptor);        User user = (User)session.load(User.class,new Long(39));        System.out.println("User name:"+user.getName());   session.close();      } 

  看結果,我們得到了:

Hibernate: select user0_.USER_ID as USER1_0_0_, user0_.USER_NAME as USER2_0_0_, user0_.age as age0_0_ from USER user0_ where user0_.USER_ID=? User to be loaded=>123shun:0 User name:shun 

  我們已經把原來的123給去掉了,在真正加載后進行了相關的處理,不過這個并不是真正加載前的處理,有點投機的嫌疑。但也不失為一個考慮的方案。Interceptor也許用得最多的還是在日志的相關處理上,比如我們需要對每次操作都進行相應的日志記錄,那么Interceptor是一個很好的選擇。

Collection
記得我們在以前例子中一對多中用到的Set,還有印象么,如果沒有趕快去查一下資料,回顧一下。今天我們就圍繞著這些Collection來進行學習。
 還是不廢話了,我們直接進入正題。
 1)首先我們來學習一下Set。大家都知道JAVA util包里面也有一個Set,那么hibernate里面的set和java的set和什么區別和聯系呢?我們打開hibernate的API,找到Set,可以看到。

201613141916915.png (494×271)

我們看到的就是這樣一個hibernate的集合的父類,它是一個抽象類,有一系列具體的實現類,我們繼續看到下面的方法時,發現這個類實現上是對java集合的封裝,這樣我們就明白啦,所謂的hibernate的Set實際上也只是封裝了java的Set。
 那么,Set中不允許重復元素的這個特點是否也在hibernate中呢?答案當然是肯定啦。
 我們這里不看這些,我們以前在學習映射時是直接把屬性和所關聯的類進行關聯,但今天我們不這樣啦,我們用另外一種方法,只是關聯一個字符串,看看有什么問題。
 但在看這個問題前,我們先來看看,java中的String比較。
我們看到的就是這樣一個hibernate的集合的父類,它是一個抽象類,有一系列具體的實現類,我們繼續看到下面的方法時,發現這個類實現上是對java集合的封裝,這樣我們就明白啦,所謂的hibernate的Set實際上也只是封裝了java的Set。
 那么,Set中不允許重復元素的這個特點是否也在hibernate中呢?答案當然是肯定啦。
 我們這里不看這些,我們以前在學習映射時是直接把屬性和所關聯的類進行關聯,但今天我們不這樣啦,我們用另外一種方法,只是關聯一個字符串,看看有什么問題。
 但在看這個問題前,我們先來看看,java中的String比較。

public static void main(String[] args) {    String s1 = "shun1";   String s2 = "shun1";   System.out.println("s1==s2:"+(s1==s2));      } 

    相信很多童鞋都知道答案是true。
在進行例子前先看一下我們的映射文件,映射類那些就不寫了:
 這是TUser的映射文件:

<class name="TUser" table="t_user" dynamic-insert="true" dynamic-update="true">   <id name="id" column="id">     <generator class="native" />   </id>   <property name="name" type="java.lang.String" column="name"/>   <property name="age" type="java.lang.Integer" column="age"/>   <set name="addresses" cascade="all" table="t_address">     <key column="user_id" />     <!-- <one-to-many class="Address"/> -->     <element column="address" type="string" />   </set>    </class> 

  接下來是Address的映射文件:

<class name="Address" table="t_address" dynamic-insert="false" dynamic-update="false">   <id name="id" column="id" type="java.lang.Integer">     <generator class="native" />   </id>   <property name="address" column="address" type="java.lang.String" />   <many-to-one name="user" class="TUser"      column="user_id" not-null="true"></many-to-one>  </class> 

  童鞋們看清楚了,我在TUser中的Set里面把one-to-many注釋了而用了element,這里先不管它有什么問題,我們先看數據庫:
 這是t_address表:

201613142004701.png (281×148)

下面是t_user表:

201613142019445.png (264×111)

我們可以看到id為4的User對應了三個地址,接下來,我們來看一下測試方法:

public static void main(String[] args) {        Configuration cfg = new Configuration().configure();   SessionFactory sessionFactory = cfg.buildSessionFactory();   Session session = sessionFactory.openSession();        TUser user = (TUser)session.load(TUser.class,new Integer(4));   Set set = user.getAddresses();   session.close();     System.out.println("address size:"+set.size()); } 

    很簡單的一個查詢類,只是取出了這個結果而已,我們看到一個奇怪的現象:

address size:1 

  這是結果!
 你肯定會說,肯定錯了吧,是hibernate的bug。這里肯定高興啦,總算可以提交一個bug了,以前跳槽的時候可以大聲說我為hibernate提交過bug。哈哈,但很遺憾,這并不是bug。
 剛才說了我們前面的那個字符串比較的是為這里作鋪墊的,那么怎么鋪呢?
 我們在配置文件中用Set,并且是通過String字符來進行關聯的,那么它首先在數據庫中取出放進Set中的時候會先判斷該關聯字符的值是否是相等的,這里由于我們的值都是相等的(這里我們暫時不深究它是怎么進行比較的),我們只需要知道當我們用字符串來進行比較的時候,我們又陷入了JAVA中的字符串陷阱了。查出來只有一條,那么刪除呢,刪除的時候就比較麻煩啦,它會把所有相同的記錄都刪除。
 那么我們來看一下刪除的:

TUser user = (TUser)session.load(TUser.class,new Integer(4));      Transaction tx = session.beginTransaction(); Object obj = user.getAddresses().iterator().next();      user.getAddresses().remove(obj);      tx.commit(); session.close(); 

  這里hibernate輸出的語句是:

Hibernate: delete from t_address where user_id=? 

  相信什么時候大家都知道了,是刪除該用戶下的所有地址。這沒得選擇,只能全部都刪除。
 所以在真正的開發中需要注意。
 
 2)上面我們講了Set,好像用著不怎么爽啊,有那么個陷阱,但沒辦法,Set是我們用得最多的,而且一般也不會有人直接去關聯字符串吧。但很多人還是會不爽,那么hibernate也就應大家要求搞多了一個Bag(也許不是應要求,可能它們里面也有人不滿,哈哈)。
 我們先來看看它的基本用法:
 首先我們需要把前面的TUser的映射文件中的Set標簽修改為:

<bag name="addresses" lazy="true" table="t_address">   <key column="user_id" />   <element type="string" column="address" /> </bag> 

  并且相應的實體類需要把addresses的類型修改為List類型。
 這里我們重新添加三個地址:

201613142111318.png (283×144)

我們運行測試代碼:

public static void main(String[] args) {      Configuration cfg = new Configuration().configure();   SessionFactory sessionFactory = cfg.buildSessionFactory();   Session session = sessionFactory.openSession();        TUser user = (TUser)session.load(TUser.class,new Integer(4));        System.out.println("address size:"+user.getAddresses().size());   session.close(); } 

 
   這里我們看到了:

address size:3 

  這次我們已經全部都可以看到了,不管有沒有重復。
 
 但我們剛才看了一個刪除的問題,Bag在這里還是沒有解決,需要借助idBag。我們看到配置文件,需要如下的修改:

idbag name="addresses" table="t_address" lazy="true">   <collection-id type="int" column="id">     <generator class="identity" />   </collection-id>   <key column="user_id" />   <element type="string" column="address" /> </idbag> 

  我們看到它只比bag多了一個collection-id進行表明要刪除的記錄號。
 當我們重新運行刪除的代碼:

TUser user = (TUser)session.load(TUser.class,new Integer(4));    Transaction tx = session.beginTransaction(); Object obj = user.getAddresses().iterator().next(); user.getAddresses().remove(obj);      tx.commit(); 

  我們看到輸出語句為:

Hibernate: delete from t_address where id=? 

  這次并不是通過user_id來進行刪除,而是根據t_address的ID來進行刪除,這說明它真正刪除我們需要刪除的那條記錄。
 我們看到數據庫,現在記錄是:

201613142156751.png (279×123)

我們已經把第一條記錄給刪了,正確了。
 
 3)看了上面兩種方法,我們再來看一下MAP,它跟上面兩個最大的不同就是可以進行鍵值的對應。直接看代碼,直觀點:
 首先,我們需要修改配置文件:

<map name="addresses" table="t_address" lazy="true">   <key column="user_id" />   <index type="string" column="type" />   <element type="string" column="address" /> </map> 

  它和前面兩個最大的不同就是有一個index,這相當于我們在java中map的key,我們通過這個來取出相對應的記錄。記住,改完這里還要改相應的實體類,需要把addresses屬性的類型改成Map。
 看看數據庫的數據:

201613142220775.png (371×146)

這里我們看到有兩個office和一個home,那么office是拿哪個呢?
 不要急,我們運行一下測試代碼就知道了:

TUser user = (TUser)session.load(TUser.class,new Integer(4));    System.out.println(user.getAddresses().get("home")); System.out.println(user.getAddresses().get("office")); 
ShanWei ShangHai 

  對,如結果可知,我們取得的是后面那個,這跟Map的原理一樣,后面存入的值會覆蓋前面的值(如果它們是同一個key的情況下)。
 Map是比較簡單的,相當前兩個來說。
 
 4)最后一個我們來看一下List。List與前幾種又有不同,不同在它可以進行排序。
 我們來看一下它是怎么實現的:
 首先我們還是修改一下映射文件:

<list name="addresses" table="t_address" lazy="true">   <key column="user_id" />   <index type="string" column="idx" />   <element type="string" column="address" /> </list> 

  它和Map的配置差不多,但index的屬性是不一樣的,Map中的index是作為key來取得值,而List的index是作為排序的。
 我們看數據庫:

201613142257115.png (444×147)

我們設了三個值,順序分別為0,1,2。
 下面我們運行代碼來更改0,2的值:

TUser user = (TUser)session.load(TUser.class,new Integer(4));    Transaction tx = session.beginTransaction(); Object obj1 = user.getAddresses().get(0); Object obj2 = user.getAddresses().get(2);      user.getAddresses().set(0,obj2); user.getAddresses().set(2,obj1);      tx.commit(); 

   我們看到結果:

201613142322811.png (443×147)

我們看到,0,2已經調換了,當然這也只是調換了idx的值。但這已經基本上實現了排序的功能了。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 泌阳县| 逊克县| 望都县| 麻江县| 峡江县| 香格里拉县| 台湾省| 孟津县| 扬中市| 孟州市| 阳原县| 峡江县| 稻城县| 余江县| 万山特区| 探索| 苗栗市| 广宗县| 新乡市| 龙海市| 永定县| 临邑县| 阳东县| 宝清县| 娱乐| 黄浦区| 济南市| 桃园县| 磴口县| 金川县| 宁强县| 竹山县| 莆田市| 马尔康县| 宜君县| 斗六市| 五大连池市| 修水县| 安龙县| 利津县| 罗定市|