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”)来指明主控方。

猜你喜欢

转载自blog.csdn.net/qq_26564827/article/details/78657879