Java的Hibernate框架中一對多的單向和雙向聯系關系映照。本站提示廣大學習愛好者:(Java的Hibernate框架中一對多的單向和雙向聯系關系映照)文章只能為提供參考,不一定能成為您想要的結果。以下是Java的Hibernate框架中一對多的單向和雙向聯系關系映照正文
1、一對多單向聯系關系映照
一對多關系的對象模子在平常生涯中也常常看到,就拿先生和班級來講,一個班級裡有多個先生,所以班級和先生的關系是一對多的關系,映照到對象模子中,以下圖:
對象模子解釋了這類一對多的關系是由一的一端來保護的,那末映照成關系模子就是一個班級字段上面會有多個先生,如許就構成了一對多的關系,經由過程班級可以或許查詢取得先生信息,對應的關系模子以下圖:
1、根本設置裝備擺設
有了對象模子接上去就讓它們映照為對應的關系代碼,在停止關系映照時須要在一的一端添加<one-to-many>標簽,別的還須要在一的一端添加Set屬性,它支撐延遲加載,然後在映照文件添加set標簽,並指明一對多的關系,如許就可以夠在一的一端查詢獲得多的一端。
Classes類及映照文件:
它是模子中最主要的一端,在該端須要添加對應的set屬性,並在設置裝備擺設文件中添加set標簽,在set標簽中設置裝備擺設響應的<one-to-many>對象,詳細Classes.java對象代碼以下:
package com.src.hibernate; import java.util.Set; public class Classes { private int id; 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; } private String name; //Set支撐延遲加載 private Set students; public Set getStudents() { return students; } public void setStudents(Set students) { this.students = students; } }
Classes對象中應用了set屬性,然則只是解釋了延遲加載的屬性,並沒無為屬性設置裝備擺設對應的對象,屬性的對象是要在映照文件中來設置裝備擺設的,須要添加set標簽,並在set標簽中添加<one-to-many>標簽,詳細以下代碼:
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="com.hibernate.Classes" table="t_classes"> <id name="id"> <generator class="native"/> </id> <property name="name"/> <set name="students"> <key column="classesid"></key> <one-to-many class="com.hibernate.Student"></one-to-many> </set> </class> </hibernate-mapping>
對應的Student對象中的代碼和映照文件不須要甚麼特別的設置裝備擺設,只須要依照平日的寫法編寫便可,詳細的設置裝備擺設辦法不再胪陳,很簡略。設置裝備擺設好後須要生成對應的SQL語句,將對象模子轉化為關系模子時Hibernate生成響應的語句以下:
alter table t_student drop foreign key FK4B9075705E0AFEFE drop table if exists t_classes drop table if exists t_student create table t_classes (id integer not null auto_increment, name varchar(255), primary key (id)) create table t_student (id integer not null auto_increment, name varchar(255), classesid integer, primary key (id)) alter table t_student add index FK4B9075705E0AFEFE (classesid), add constraint FK4B9075705E0AFEFE foreign key (classesid) references t_classes (id)
生成的對應的關系模子以下圖:
比較SQL語句和關系模子,響應的表之間的聯系關系是經由過程外鍵來保護的,起首是創立兩張表,並指定表的主鍵,最初添加一對多的外鍵聯系關系關系。
2、根本操作
在對數據庫的操作不過是讀和寫兩種,修正也屬於寫的一種,接上去看看是若何向數據庫中寫入和讀取操作的。
(1)寫入數據:
寫入數據須要留意的是一對多的關系,所以在添加的時刻須要添加多個先生類,別的因為在classes中添加了對應的set屬性,所以在添加Student對象時應當應用HashSet來添加,如許既可完成一對多的關系,詳細以下代碼:
public void testSave2(){ Session session=null; try{ session=HibernateUtils.getSession(); session.beginTransaction(); Student student1=new Student(); student1.setName("zhangsan"); session.save(student1); Student student2=new Student(); student2.setName("lisi"); session.save(student2); Classes classes=new Classes(); classes.setName("ClassOne"); Set students=new HashSet(); students.add(student1); students.add(student2); classes.setStudents(students); //可以勝利保留數據 //然則會收回過剩的update語句來保持關系,由於是一對多的緣由 session.save(classes); session.getTransaction().commit(); }catch(Exception e){ e.printStackTrace(); session.getTransaction().rollback(); }finally{ HibernateUtils.closeSession(session); } }
那末運轉下面的測試用例生成的對應的數據寫入到數據庫中後以下圖:
(2)讀取數據:
寫入操作絕對簡略,只須要把一切加載的對象都添加到Transient狀況下,運轉響應的辦法便可以拔出內容,然則對應的讀取操作就會略微龐雜點,由於須要迭代獲得一切的先生對象,所以這類一對多的關系效力其實不很高,詳細代碼以下:
package com.test.hibernate; import java.util.Iterator; import java.util.Set; import com.src.hibernate.*; import junit.framework.TestCase; import org.hibernate.Session; public class One2ManyTest extends TestCase { public void testLoad1(){ Session session=null; try{ session=HibernateUtils.getSession(); session.beginTransaction(); //獲得主鍵為5的班級信息 Classes classes=(Classes)session.load(Classes.class,5); //打印班級信息 System.out.println("classes.name="+classes.getName()); //設置先生聚集,經由過程班級加載先生聚集 Set students=classes.getStudents(); //迭代聚集,打印聚集中先生的信息 for(Iterator iter=students.iterator();iter.hasNext();){ Student student=(Student)iter.next(); System.out.println("student.name="+student.getName()); } session.getTransaction().commit(); }catch(Exception e){ e.printStackTrace(); session.getTransaction().rollback(); }finally{ HibernateUtils.closeSession(session); } } }
生成的響應的語句及信息以下語句:
Hibernate: select classes0_.id as id1_0_, classes0_.name as name1_0_ from t_classes classes0_ where classes0_.id=? classes.name=ClassOne Hibernate: select students0_.classesid as classesid1_, students0_.id as id1_, students0_.id as id0_0_, students0_.name as name0_0_ from t_student students0_ where students0_.classesid=? student.name=lisi student.name=zhangsan
2、一對多雙向聯系關系映照
這裡持續采取先生和班級作為示例,班級和先生之間是一對多的關系,一個班級中具有多邏輯學生,和上篇文章分歧的是這裡的關系是雙向的,也就是一的一端和多的一端同時保護聯系關系關系,所以它的對象圖以下:
對應的關系模子圖沒有太年夜的變更,由於它們之間的關系是雙向的,所以在關系模子中兩頭同時保護聯系關系關系,映照到關系模子中以下圖所示:
在一對多的單向聯系關系中映照文件只須要在一的一端停止特別設置裝備擺設便可以,應用<one-to-many>設置裝備擺設,並在對象模子中應用set迭代器來設置外聯的對象模子,然則分歧的是在雙向的聯系關系中須要在多的一端添加對應的另外一真個外鍵聯系關系,這時候候就必需在多的一端應用<many-to-one>的聯系關系關系來標明這類雙向性。
1、映照
這裡還應用Classes和Student來做示例,在Classes一真個內容和上文雷同不會產生變換,然則多的一端Student的設置裝備擺設會產生變更,也就是在映照文件中須要添加<many-to-one>標簽。
Student.hbm.xml映照文件設置裝備擺設須要添加外鍵列<many-to-one>標簽,而且該列的稱號要和Classes.hbm.xml的外鍵列的稱號分歧,詳細以下代碼:
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="com.src.hibernate.Student" table="t_student"> <id name="id"> <generator class="native"/> </id> <property name="name"/> <!-- 在多的一端Student中添加一行新的Classes列 ,而且列的稱號要和Classes.hbm.xml的列明雷同--> <many-to-one name="classes" column="classesid"></many-to-one> </class> </hibernate-mapping>
Classes.hbm.xml映照文件的設置裝備擺設和上篇文章雷同,須要留意的是在Classes.java文件中添加了set屬性映照對應了Student對象,所以在映照文件中須要添加set標簽來指導為對象模子中應用了set迭代器,詳細設置裝備擺設以下代碼:
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="com.src.hibernate.Classes" table="t_classes"> <id name="id"> <generator class="native"/> </id> <property name="name"/> <set name="students" inverse="true"> <key column="classesid"></key> <one-to-many class="com.src.hibernate.Student"></one-to-many> </set> </class> </hibernate-mapping>
2、類
映照文件的設置裝備擺設是直接對應著類來的,所以有了映照文件就可以夠寫出響應的類,雷同的有了類就可以夠曉得對應的映照文件若何編寫,那來看看響應的類代碼若何編寫。
Student.java類,須要在類中添加聯系關系的班級對象屬性,在加載Student時能取得Classes的相干信息。
package com.src.hibernate; public class Student { //聯系關系的班級對象 private Classes classes; public Classes getClasses() { return classes; } public void setClasses(Classes classes) { this.classes = classes; } //先生id private int id; public int getId() { return id; } public void setId(int id) { this.id = id; } //先生姓名 private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } }
Classes.java文件詳細代碼內容見上篇文章,這裡就不在胪陳。
有了對象模子接上去生成關系模子,生成的SQL語句以下:
alter table t_student drop foreign key FK4B907570FC588BF4 drop table if exists t_classes drop table if exists t_student create table t_classes (id integer not null auto_increment, name varchar(255), primary key (id)) create table t_student (id integer not null auto_increment, name varchar(255), classesid integer, primary key (id)) alter table t_student add index FK4B907570FC588BF4 (classesid), add constraint FK4B907570FC588BF4 foreign key (classesid) references t_classes (id)
3、數據操作
樹立表構造後來編寫測試辦法來驗證數據的操作,起首來看看數據的拔出,向表構造中拔出數據,寫入數據時會有兩種情形,一種是起首創立一個Classes對象,並將對象寫入到數據庫中,然後創立Student對象,在Classes對象中添加先生對象;別的一種是先創立先生對象,並將先生對象寫入數據庫中,然後創立Classes對象將先生對象參加到Classes對象中,這兩品種型的操作最初是不雷同的,來比較下。
3.1 先寫班級後寫先生
先把班級寫入到數據庫中後,Classes對象進入了Transient狀況,並在數據庫中有了一行,這時候再寫Student對象,Student對象會查找對應的Classes的主鍵將其寫入到表中,所以此時關系模子中的數據都長短空的,保留的代碼以下:
public void testSave(){ Session session=null; try{ //創立session對象 session=HibernateUtils.getSession(); //開啟事務 session.beginTransaction(); //創立班級對象,將班級對象寫入到數據庫中 Classes classes=new Classes(); classes.setName("class"); session.save(classes); //創立先生1對象,將先生對象寫入到數據庫中 Student student1=new Student(); student1.setName("zhangsan"); student1.setClasses(classes); session.save(student1); //創立先生2對象,將先生對象寫入到數據庫中 Student student2=new Student(); student2.setName("lisi"); student2.setClasses(classes); session.save(student2); session.getTransaction().commit(); }catch(Exception e){ e.printStackTrace(); session.getTransaction().rollback(); }finally{ HibernateUtils.closeSession(session); } }
對應的寫入數據庫中的信息列表以下圖:
3.2 先寫先生後寫班級
先把先生寫入到數據庫中此時由於先生表須要獲得對應的班級列的主鍵信息,然則由於班級信息轉化到Transient狀況,所以在寫退學生信息時會有null值,代碼以下:
寫入後對應的數據庫視圖以下:
比較兩種寫入操作,由於兩個寫入的前後次序分歧所以湧現了分歧的成果,但由於是雙向的聯系關系關系所以在寫入時其實不會產生異常。
4、讀取操作
絕對於寫入數據而言,讀取數據就變得很簡略了,由於是雙向的聯系關系所以數據的讀取也是雙向的,可以從任何一端讀取另外一真個信息,以下代碼:
public void testLoad1(){ Session session=null; try{ session=HibernateUtils.getSession(); session.beginTransaction(); //經由過程班級讀取先生信息 Classes classes=(Classes)session.load(Classes.class,1); System.out.println("classes.name="+classes.getName()); Set students=classes.getStudents(); for(Iterator iter=students.iterator();iter.hasNext();){ Student student=(Student)iter.next(); System.out.println("student.name="+student.getName()); } //經由過程先生信息讀取班級信息 Student stu=new Student(); stu=(Student)session.load(Student.class, 1); System.out.println("經由過程先生加載班級信息Classes.id= "+stu.getClasses().getId()); session.getTransaction().commit(); }catch(Exception e){ e.printStackTrace(); session.getTransaction().rollback(); }finally{ HibernateUtils.closeSession(session); } }
運轉下面的測試語句,生成的對應的語句信息以下:
Hibernate: select classes0_.id as id1_0_, classes0_.name as name1_0_ from t_classes classes0_ where classes0_.id=? classes.name=class Hibernate: select students0_.classesid as classesid1_, students0_.id as id1_, students0_.id as id0_0_, students0_.name as name0_0_, students0_.classesid as classesid0_0_ from t_student students0_ where students0_.classesid=? student.name=lisi student.name=zhangsan
經由過程先生加載班級信息Classes.id= 1