先說一段廢話吧,本打算每天把所學的知識總結為博客的,但是昨天為什么沒有寫呢?沒有學習嗎?No,那是為什么?貪玩,對,這位同學說對了,老實說昨天感覺身體不怎么舒服,大家都知道,這其實就是為自己懶找借口,好吧,廢話先嘮到這兒,下面進入正題。
先說說概念吧
在持久化類中,有時會使用到值類型的對象屬性,所謂值類型的對象,是指它對應的類沒有對象標識符屬性,也就是我們在前面所說的OID,只能作為一個持久化類的屬性使用。如果持久化類中一個值類型的集合,那么就需要一張額外的數據庫表來保存這個值類型集合的數據,這張表被稱為集合表。
需要注意的一點是,hibernate3.0以后開始支持大部分重要的JDK集合接口映射,當然,現在的開發基本上都是使用3.0以后的版本吧,
為此,我們在項目中新建一個實體類吧,我取名StudentSet.java,給它簡單地賦予幾個屬性,其中比較特別的屬性就是hoppy屬性,它是一個Set集合類型的,表現為一多關系:
package com.joe.entity; import java.util.Set; /** * * @author Joe * StudentSet java bean */ public class StudentSet { private int id; private String name; private int age; private Set<String> hobby; /** * 無參的構造函數 */ public StudentSet(){ } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Set<String> getHobby() { return hobby; } public void setHobby(Set<String> hobby) { this.hobby = hobby; } }
在配置實體關心映射文件的時候,要特別注意對於set標簽的配置:<set>元素用來映射java.util.Set類型的屬性,常用的屬性和子元素有:
- name屬性:對應實體類中Set集合屬性
- table屬性:當前Set集合所對應的表結構
- <key>子元素:Set集合對應的表結構的外鍵列
- <element>子元素:保存集合中所存貯的數據
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-mapping SYSTEM "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd" > <hibernate-mapping> <!-- 一個class標簽對應一個實體類,name屬性指定實體類名稱,table屬性指定關聯的數據庫表 --> <class name="com.joe.entity.StudentSet" table="stu_set_tab"> <!-- 主鍵 --> <id name="id" column="stu_id"> <!-- 提供ID自增的策略 native會根據數據庫自行判斷 --> <generator class="native"></generator> </id> <!-- 其他屬性,name對應實體類的屬性,column對應關系型數據庫表的列 --> <property name="name" column="stu_name"></property> <property name="age" column="stu_age"></property> <set name="hobby" table="hobby_tab"> <key column="student_id"></key> <element type="string" column="hobby"></element> </set> </class> </hibernate-mapping>
其中key是hobby_tab的外鍵,element元素標簽是映射到數據庫中的集合的字段,另外,一定要為element標簽設置type屬性,否則是會拋異常的。編寫好了過后,不要忘了在hibernate.cfg.xml文件中添加映射,接下來,在test文件夾下的測試包中新建一個StudentSetTest.java測試類,在該類下,先添加下面的方法:
@Test public void createTable() { Configuration cfg = new Configuration().configure(); SchemaExport se = new SchemaExport(cfg); se.create(true, true); }
這個方法就不介紹了,執行該方法,看看hibernate都做了些什么?
可以發現,除了創建stu_set_tab表以外,還創建了一張名為hobby_tab的表,並且把student_id設置為hobby_tab的外鍵。
測試添加
緊跟上面的步伐,添加一個add()方法:
/** * 添加的方法 */ @Test public void add(){ Transaction tx=null; Session session=null; try{ session=HibernateUtils.getSession(); tx=session.beginTransaction(); StudentSet student=new StudentSet(); student.setName("zhangsan"); student.setAge(20); @SuppressWarnings({ "rawtypes", "unchecked" }) Set<String> set=new HashSet(); set.add("basketball"); set.add("swimming"); student.setHobby(set); session.save(student); tx.commit(); }catch(HibernateException he){ if(tx!=null){ tx.rollback(); } he.printStackTrace(); }finally{ HibernateUtils.closeSession(session); } }
調用session的save()方法,測試該方法,在看看hibernate又為我們做了什么?
有點可惜,屏幕不夠大,看不完整,但思路是完整的,這幾句sql還是好理解的,就是簡單的插入操作,不再多言。
get()方法
這個測試更有趣一點:
/** * 查詢方法 */ @Test public void findAll(){ Transaction tx=null; Session session=null; try{ session=HibernateUtils.getSession(); tx=session.beginTransaction(); StudentSet stu=(StudentSet)session.get(StudentSet.class, 1); System.out.println(stu.getId()+stu.getName()+stu.getAge()); tx.commit(); }catch(HibernateException he){ if(tx!=null){ tx.rollback(); } he.printStackTrace(); }finally{ HibernateUtils.closeSession(session); } }
在次測試,看看控制台的輸出信息:
咦,為什么沒有查詢hobby_tab表呢?從上面的程序代碼中,我們並沒有訪問hobby屬性,改進程序代碼,添加訪問hobby屬性的代碼:
//訪問hobby屬性 Set<String> hobby=stu.getHobby(); for(String str:hobby){ System.out.println(str); }
再次測試,結果應該都能猜到的,
如我們所料,hibernate執行了兩條sql語句。先根據id查詢學習的基本信息,再根據id在hobby_tab中查詢對應的數據。前面不是說過了嗎?只有訪問對象的非對象表示符(OID)屬性的時候,才會發起select語句,體現了hibernate的延遲加載、懶加載的特性。
好吧,把昨天的博客補上了,稍稍有點簡陋,當然還有很多沒有總結到的,也還有很多需要修正的,希望園子里的大神們可以給我提些意見和建議。