詳解Java的Hibernate框架中的Interceptor和Collection。本站提示廣大學習愛好者:(詳解Java的Hibernate框架中的Interceptor和Collection)文章只能為提供參考,不一定能成為您想要的結果。以下是詳解Java的Hibernate框架中的Interceptor和Collection正文
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辦法中停止了修正。
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,可以看到。
我們看到的就是如許一個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表:
上面是t_user表:
我們可以看到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類型。
這裡我們從新添加三個地址:
我們運轉測試代碼:
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來停止刪除,這解釋它真正刪除我們須要刪除的那筆記錄。
我們看到數據庫,如今記載是:
我們曾經把第一筆記錄給刪了,准確了。
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。
看看數據庫的數據:
這裡我們看到有兩個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是作為排序的。
我們看數據庫:
我們設了三個值,次序分離為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();
我們看到成果:
我們看到,0,2曾經更換了,固然這也只是更換了idx的值。但這曾經根本上完成了排序的功效了。