Hibernate 映射關係(基於註解)

提示:表與表之間的映射關係通過外鍵或中間表建立聯繫:

  • 單向外鍵映射關係:這裏主要是指在兩個映射表對象類(一對一關係)之間只有一方包含另一方的引用,比如映射對象類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&amp;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類對應數據表
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”)來指明主控方。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章