提示:表與表之間的映射關係通過外鍵或中間表建立聯繫:
- 單向外鍵映射關係:這裏主要是指在兩個映射表對象類(一對一關係)之間只有一方包含另一方的引用,比如映射對象類A與映射表對象B之間,如果只有A中有一個屬性是對B的引用 private B b;那麼就稱爲單向外鍵關係。
- 雙向外鍵映射關係;這裏指雙方都包含一方的引用,但如果是沒有中間表,那麼就要指定主控方與被控方。
上面所說的單向外鍵關係與映射外鍵關係雖然存在着引用的差別,但是(比如一對一或者多對多等)在建表的時候,表的結構是一樣的,比如主控方是A被控方是B,兩種情況下表結構一樣,都是A對應的表中包含B的主鍵作爲外鍵,不同的是,單向外鍵關係,從主控方的對象可以獲取被控方對象,而雙向外鍵關係則可以從任何一方獲取另一方的對象。差別在於hibernate操作數據庫的時候,是否連帶關聯操作被控方。
這裏使用的是Hibernate5 而且裏面有一個包與javaEE庫有衝突 :在用@JoinColumn(name=”pid”)創建外鍵一直報錯 是因爲 javax.persistence.jar與 hibernate中的hibernate-jpa-2.1-api-1.0.0.Final.jar衝突,可以先刪除javaEE類庫然後在重新添加就可以了。
這裏使用的是hibernate5
配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd" >
<hibernate-configuration>
<session-factory>
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="connection.url">jdbc:mysql:///hibernate?useUnicode=true&characterEncoding=UTF8</property>
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="connection.username">root</property>
<property name="connection.password">12345</property>
<property name="show_sql">true</property>
<property name="format_sql">true</property>
<property name="hbm2ddl.auto">update</property>
<property name="hibernate.current_session_context_class">thread</property>
<!--
<mapping class="com.hibernate.environment.Students"/>
<mapping class="com.hibernate.environment.Person"/>
<mapping class="com.hibernate.environment.Dog"/>
-->
<mapping class="com.hibernate.relationship.oneTone.IdCardOneToOneFK"/>
<mapping class="com.hibernate.relationship.oneTone.PersonOneToOneFK"/>
</session-factory>
</hibernate-configuration>
1、一對一單向外鍵關係
主控方person類(含有IdCard類引用,並且數據庫表中含有IdCard對應表字段作爲外鍵)
package com.hibernate.relationship.oneTone;
import java.io.Serializable;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToOne;
//一對一單向外鍵
@Entity
public class PersonOneToOneFK {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY ) //整型可以指定默認增長策略
private int wid;
private int age;
@OneToOne(cascade=CascadeType.ALL) //全級聯關係
@JoinColumn(name="pid",unique=true) //指定外鍵名稱爲pid
private IdCardOneToOneFK idCard;
public PersonOneToOneFK() {
}
public PersonOneToOneFK( int age, IdCardOneToOneFK idCard) {
this.age = age;
this.idCard = idCard;
}
public int getWid() {
return wid;
}
public void setWid(int wid) {
this.wid = wid;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public IdCardOneToOneFK getIdCard() {
return idCard;
}
public void setIdCard(IdCardOneToOneFK idCard) {
this.idCard = idCard;
}
}
被控方IdCard類
package com.hibernate.relationship.oneTone;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import org.hibernate.annotations.GenericGenerator;
@Entity
public class IdCardOneToOneFK {
@Id
@GeneratedValue(generator="pid")
@GenericGenerator(name="pid",strategy="assigned")
@Column(length=18)
private String pid; //主鍵是字符串類型需要指定主鍵生成器以及生成策略,同時還要指定長度,否則默認255長度會報錯不能作爲主鍵長度
@Column(length=24)
private String name;
public IdCardOneToOneFK() {
super();
// TODO Auto-generated constructor stub
}
public IdCardOneToOneFK(String pid, String name) {
super();
this.pid = pid;
this.name = name;
}
public String getPid() {
return pid;
}
public void setPid(String pid) {
this.pid = pid;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
生成數據表結構代碼:
這裏用的hibernate5與之前版本有點差別
@Test
public void createTable(){
Configuration configuration = new Configuration();
System.out.println(configuration);
ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().configure().build();
MetadataImplementor metadata = (MetadataImplementor) new MetadataSources( serviceRegistry ).buildMetadata();
new SchemaExport(metadata).create(true, true);
}
生成數據表結構:
Person類對應數據表
IdCard類對應數據表
注意:在保存對象的時候,先保存IdCard類,然後再保存Person類,因爲主控方包含被控方的引用,在數據庫表中引用被控方字段作爲外鍵,所以需要先有保存IdCard,用其字段值(這裏是它的主鍵)作爲外鍵。
2、一對一雙向外鍵關係
Person類
package com.hibernate.relationship.oneTone;
import java.io.Serializable;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToOne;
@Entity
public class PersonOneToOneBFK {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY )
private int wid;
private int age;
@OneToOne(cascade=CascadeType.ALL)
@JoinColumn(name="pid",unique=true)
private IdCardOneToOneBFK Card;
public PersonOneToOneBFK() {
}
public PersonOneToOneBFK( int age, IdCardOneToOneBFK Card) {
this.age = age;
this.Card = Card;
}
public int getWid() {
return wid;
}
public void setWid(int wid) {
this.wid = wid;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public IdCardOneToOneBFK getCard() {
return Card;
}
public void setCard(IdCardOneToOneBFK card) {
Card = card;
}
}
IdCard類
package com.hibernate.relationship.oneTone;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import org.hibernate.annotations.GenericGenerator;
@Entity
public class IdCardOneToOneBFK {
private String pid;
private String name;
private PersonOneToOneBFK person;
public IdCardOneToOneBFK() {
super();
// TODO Auto-generated constructor stub
}
public IdCardOneToOneBFK(String pid, String name) {
super();
this.pid = pid;
this.name = name;
}
@Id
@GeneratedValue(generator="pid")
@GenericGenerator(name="pid",strategy="assigned")
@Column(length=18)
public String getPid() {
return pid;
}
public void setPid(String pid) {
this.pid = pid;
}
@Column(length=24)
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@OneToOne(mappedBy="Card") //裏面表示主控方里面對該類變量的引用名稱
public PersonOneToOneBFK getPerson() {
return person;
}
public void setPerson(PersonOneToOneBFK person) {
this.person = person;
}
}
Person類對應的數據表
IdCard類對應的數據表
注意:單向外鍵與雙向外鍵在建表結構的時候是一樣的,區別是在獲取其中一個對象能否從獲取另一個對象(是否有引用),雙向外鍵關係需要指定一方來管理之間的關係比如在IdCard類中@OneToOne(mappedBy=”Card”)用來指定控制管理權在Person類中。
3、一對多雙向外鍵關係(多的一方持有外鍵)
Student類
package com.hibernate.realtionship.oneTmany;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import org.hibernate.annotations.GenericGenerator;
@Entity
public class Student {
private String sid;
private String sname;
private int age;
private ClassRoom classroom;
public Student() {
super();
// TODO Auto-generated constructor stub
}
public Student(String sid, String sname, int age, ClassRoom classroom) {
super();
this.sid = sid;
this.sname = sname;
this.age = age;
this.classroom = classroom;
}
@Id
@GeneratedValue(generator="sid")
@GenericGenerator(name="sid",strategy="assigned")
@Column(length=10)
public String getSid() {
return sid;
}
public void setSid(String sid) {
this.sid = sid;
}
@Column(length=24)
public String getSname() {
return sname;
}
public void setSname(String sname) {
this.sname = sname;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@ManyToOne(cascade=CascadeType.ALL,fetch=FetchType.EAGER)
@JoinColumn(name="cid")
public ClassRoom getClassroom() {
return classroom;
}
public void setClassroom(ClassRoom classroom) {
this.classroom = classroom;
}
}
Classroom類
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import org.hibernate.annotations.GenericGenerator;
@Entity
public class ClassRoom {
private String cid;
private String cname;
private Set<Student> stu;
public ClassRoom() {
super();
// TODO Auto-generated constructor stub
}
public ClassRoom(String cid, String cname, Set<Student> stu) {
super();
this.cid = cid;
this.cname = cname;
this.stu = stu;
}
@Id
@GeneratedValue(generator="cid")
@GenericGenerator(name="cid",strategy="assigned")
@Column(length=10)
public String getCid() {
return cid;
}
public void setCid(String cid) {
this.cid = cid;
}
@Column(length=40)
public String getCname() {
return cname;
}
public void setCname(String cname) {
this.cname = cname;
}
@OneToMany(cascade=CascadeType.ALL,fetch=FetchType.LAZY)
@JoinColumn(name="cid")
public Set<Student> getStu() {
return stu;
}
public void setStu(Set<Student> stu) {
this.stu = stu;
}
}
數據表結構:
Student類對應的數據庫表結構
Classroom類對應的數據庫表結構
注意:同樣是雙向外鍵關聯,在 建造數據表的時候,只有一方持有外鍵,在數據表結構沒差別,但在hibernate獲取對象的時候有差別。這裏相當於主控方是Students,Students裏面用到@ManyToOne(cascade=CascadeType.ALL,fetch=FetchType.EAGER)
@JoinColumn(name=”cid”)使用這些指明級聯關係,以及加載方式爲積極加載,同時指明外鍵爲cid,同樣在Classroom中,對應用@OneToMany(cascade=CascadeType.ALL,fetch=FetchType.LAZY)
@JoinColumn(name=”cid”)同樣也是指明外鍵爲cid(並不是指明Classroom在Student類中的引用名稱)。
4、多對一的外鍵單向關聯關係(多的一方持有外鍵關係)
Student類
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import org.hibernate.annotations.GenericGenerator;
@Entity
public class Student {
@Id
@GeneratedValue(generator="sid")
@GenericGenerator(name="sid",strategy="assigned")
@Column(length=8)
private String sid;
@Column(length=24)
private String sname;
private int age;
@ManyToOne(cascade=CascadeType.ALL,fetch=FetchType.EAGER)
@JoinColumn(name="cid",referencedColumnName="cId")
private Classroom classroom;
public Student() {
super();
// TODO Auto-generated constructor stub
}
public Student(String sid, String sname, int age, Classroom classroom) {
super();
this.sid = sid;
this.sname = sname;
this.age = age;
this.classroom = classroom;
}
public String getSid() {
return sid;
}
public void setSid(String sid) {
this.sid = sid;
}
public String getSname() {
return sname;
}
public void setSname(String sname) {
this.sname = sname;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Classroom getClassroom() {
return classroom;
}
public void setClassroom(Classroom classroom) {
this.classroom = classroom;
}
}
Classroom類
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import org.hibernate.annotations.GenericGenerator;
@Entity
public class Classroom {
@Id
@GeneratedValue(generator="cid")
@GenericGenerator(name="cid",strategy="assigned")
@Column(length=8)
private String cid;
@Column(length=50)
private String cname;
public Classroom() {
super();
// TODO Auto-generated constructor stub
}
public Classroom(String cid, String cname) {
super();
this.cid = cid;
this.cname = cname;
}
public String getCid() {
return cid;
}
public void setCid(String cid) {
this.cid = cid;
}
public String getCname() {
return cname;
}
public void setCname(String cname) {
this.cname = cname;
}
}
數據庫表結構:
Student類對應的數據庫表結構:
Student類對應的數據表結構:
Classroom類對應的數據表結構:
注意:這裏多對一和一對多無論是雙向還是單向外鍵關係,但在建表結構上是一樣的。這裏是多的一方Student持有對方的引用,所以在保存對象的時候要先保存被控方,也就是被引用的一方。
5、多對多單向外鍵關係
Student類:
import java.util.Set;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import org.hibernate.annotations.GenericGenerator;
@Entity
public class Student {
private String sid;
private String sname;
private String major;
private Set<Teacher> teacher;
public Student() {
super();
// TODO Auto-generated constructor stub
}
public Student(String sid, String sname, String major, Set<Teacher> teacher) {
super();
this.sid = sid;
this.sname = sname;
this.major = major;
this.teacher = teacher;
}
@Id
@GeneratedValue(generator="sid")
@GenericGenerator(name="sid",strategy="assigned")
@Column(length=10)
public String getSid() {
return sid;
}
public void setSid(String sid) {
this.sid = sid;
}
@Column(length=24)
public String getSname() {
return sname;
}
public void setSname(String sname) {
this.sname = sname;
}
@Column(length=40)
public String getMajor() {
return major;
}
public void setMajor(String major) {
this.major = major;
}
@ManyToMany
@JoinTable(name="student_teacher",
joinColumns={@JoinColumn(name="sid")},
inverseJoinColumns={@JoinColumn(name="tid")}
)
public Set<Teacher> getTeacher() {
return teacher;
}
public void setTeacher(Set<Teacher> teacher) {
this.teacher = teacher;
}
}
Teacher類
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import org.hibernate.annotations.GenericGenerator;
//單向是指只有一方持有另一方的引用 而雙向指雙方都有一方的引用
@Entity
public class Teacher {
private String tid;
private String tname;
private int age;
public Teacher() {
super();
// TODO Auto-generated constructor stub
}
public Teacher(String tid, String tname, int age) {
super();
this.tid = tid;
this.tname = tname;
this.age = age;
}
@Id
@GeneratedValue(generator="tid") //有指定數id生成策略 或者使用hibernate生成器
@GenericGenerator(name="tid",strategy="assigned")
@Column(length=10)
public String getTid() {
return tid;
}
public void setTid(String tid) {
this.tid = tid;
}
@Column(length=24)
public String getTname() {
return tname;
}
public void setTname(String tname) {
this.tname = tname;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
數據庫數據表結構:
Student類對應表數據結構
Teacher類對應的表數據結構
中間表student_teacher對應的數據表結構
注意:多對多關係不能單純靠兩個表外鍵關係來關聯,而是需要一箇中間表來建立之間的關係。在其中一方添加@ManyToMany
@JoinTable(name=”student_teacher”,
joinColumns={@JoinColumn(name=”sid”)},
inverseJoinColumns={@JoinColumn(name=”tid”)}
)來創建中間表並制定其中的屬性名外鍵以及反轉屬性值,這樣就可以通過中間表來建立多對多的外鍵關係。(name是創建數據庫表的表名,後面指明創建表的主鍵值)
6、多對多雙向外鍵關係
Student類
import java.util.Set;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import org.hibernate.annotations.GenericGenerator;
@Entity //單向引用只能先添加被引用 雙向引用這都可以
public class StudentBFK {
private String sid;
private String sname;
private String major;
private Set<TeacherBFK> teacher;
public StudentBFK() {
super();
// TODO Auto-generated constructor stub
}
public StudentBFK(String sid, String sname, String major, Set<TeacherBFK> teacher) {
super();
this.sid = sid;
this.sname = sname;
this.major = major;
this.teacher = teacher;
}
@Id
@GeneratedValue(generator="sid")
@GenericGenerator(name="sid",strategy="assigned")
@Column(length=10)
public String getSid() {
return sid;
}
public void setSid(String sid) {
this.sid = sid;
}
@Column(length=24)
public String getSname() {
return sname;
}
public void setSname(String sname) {
this.sname = sname;
}
@Column(length=40)
public String getMajor() {
return major;
}
public void setMajor(String major) {
this.major = major;
}
@ManyToMany
@JoinTable(name="student_teacher",
joinColumns={@JoinColumn(name="sid")},
inverseJoinColumns={@JoinColumn(name="tid")}
)
public Set<TeacherBFK> getTeacher() {
return teacher;
}
public void setTeacher(Set<TeacherBFK> teacher) {
this.teacher = teacher;
}
}
Teacher類
import java.util.Set;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import org.hibernate.annotations.GenericGenerator;
//單向是指只有一方持有另一方的引用 而雙向指雙方都有一方的引用
@Entity
public class TeacherBFK {
private String tid;
private String tname;
private int age;
private Set<StudentBFK> student;
public TeacherBFK() {
super();
// TODO Auto-generated constructor stub
}
public TeacherBFK(String tid, String tname, int age,Set<StudentBFK> studnet) {
super();
this.tid = tid;
this.tname = tname;
this.age = age;
this.student=student;
}
@Id
@GeneratedValue(generator="tid") //有指定數id生成策略 或者使用hibernate生成器
@GenericGenerator(name="tid",strategy="assigned")
@Column(length=10)
public String getTid() {
return tid;
}
public void setTid(String tid) {
this.tid = tid;
}
@Column(length=24)
public String getTname() {
return tname;
}
public void setTname(String tname) {
this.tname = tname;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@ManyToMany(mappedBy="teacher")
public Set<StudentBFK> getStudent() {
return student;
}
public void setStudent(Set<StudentBFK> student) {
this.student = student;
}
}
數據庫數據表結構
Student類對應的數據表結構
Teacher類對應的數據表結構
Student_teacher數據表結構
注意:這裏雙向外鍵關係同樣與單向外鍵關係之間的區別在於是否有引用,以及還要有相應的配置 ,區別在於 teacher類中也包含Student的引用Set集合,同時也要有相應的配置在Student屬性上配置@ManyToMany(mappedBy=”teacher”)主控方在Student類。
總結:
》一對一關係:單向外鍵關係只有一方持有一方的引用;雙向外鍵關係雙方都持有對方的引用,則雙方對等需要用@OneToOne(mappedBy=”該類在對方的類的屬性引用”)指定主控方。
》一對多(多對一)關係:單向外鍵關係只有一方持有另一方的引用;雙向外鍵關係雙方都持有對方的引用,同時一方要有相應的配置:比如少的一方@OneToMany(cascade=CascadeType.ALL,fetch=FetchType.LAZY)
@JoinColumn(name=”cid”)指明關係外,還要指明外鍵(否則會多一個表)這裏的外鍵同樣爲少的一方的id,與多的一方相應的配置@ManyToOne(cascade=CascadeType.ALL,fetch=FetchType.EAGER)
@JoinColumn(name=”cid”)配置的外鍵名相同,這裏並沒有類似其他的指明主控方,但是可以按雙方不對等來記憶不用onetoone、manytomany的 mappedBy直接指明主控方。
》多對多關係:單向外鍵關係只有一方持有另一方的引用,雙向外鍵關係是雙方都持有對方的引用,同時還要新增配置@ManyToMany(mappedBy=”teacher”)來指明主控方。