hibernate 一对多建表实例详解 附上各个注释的含义

来源:互联网 发布:一家人颜值都高 知乎 编辑:程序博客网 时间:2024/06/03 11:32

转载:http://www.cnblogs.com/zhangshitong/p/5213992.html

这个是hibernate的一对多建表实例:一的一端是部门(Department),对的一端是员工(Employee),下面贴上成员源代码:其中@mappedBy是加在@OneToMany一端,并且它的name属性=多的那一端(N端)属性是一的那一端的属性名,mappedBy是定义在Department类中,即Department类不负责维护级联关系.即维护者是Employee类

Department类:

复制代码
package com.javabean;import java.io.Serializable;import java.util.Set;import javax.persistence.CascadeType;import javax.persistence.Column;import javax.persistence.Entity;import javax.persistence.GeneratedValue;import javax.persistence.GenerationType;import javax.persistence.Id;import javax.persistence.OneToMany;import javax.persistence.Table;@SuppressWarnings("serial")@Entity@Table(name="department")public class Department implements Serializable{        @Id    @GeneratedValue(strategy=GenerationType.AUTO)    private int id;        @Column(name="name")    private String name;        @OneToMany(mappedBy="depart",cascade=CascadeType.ALL)    private Set<Employee> emps;    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 Set<Employee> getEmps() {        return emps;    }    public void setEmps(Set<Employee> emps) {        this.emps = emps;    }    }
复制代码
复制代码
//Employee类:package com.javabean;import java.io.Serializable;import javax.persistence.Column;import javax.persistence.Entity;import javax.persistence.GeneratedValue;import javax.persistence.GenerationType;import javax.persistence.Id;import javax.persistence.JoinColumn;import javax.persistence.ManyToOne;import javax.persistence.Table;@SuppressWarnings("serial")@Entity@Table(name="employee")public class Employee implements Serializable {        @Id    @GeneratedValue(strategy=GenerationType.AUTO)    private int id;            @Column(name="name")    private String name;        @ManyToOne    @JoinColumn(name="depart_id")    private Department depart;        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 Department getDepart() {        return depart;    }    public void setDepart(Department depart) {        this.depart = depart;    }    }
复制代码

补充知识:

注释的含义学习:

双向一对一映射

class Card{

@OneToOne(optional=false,cascade={CascadeType.MERGE,CascadeType.REMOVE},mappedBy="card",fetch=FetchType.EAGER)

Person getPerson(){}

}

mappedBy 单向关系不需要设置该属性,双向关系必须设置,避免双方都建立外键字段

数据库中1对多的关系,关联关系总是被多方维护的即外键建在多方,我们在单方对象的@OneToMany(mappedby=" ")

把关系的维护交给多方对象的属性去维护关系

对于mappedBy复习下:

a) 只有OneToOne,OneToMany,ManyToMany上才有mappedBy属性,ManyToOne不存在该属性;
b) mappedBy标签一定是定义在the owned side(被拥有方的),他指向the owning side(拥有方);
c) 关系的拥有方负责关系的维护,在拥有方建立外键。所以用到@JoinColumn
d)mappedBy跟JoinColumn/JoinTable总是处于互斥的一方

cascade 设定级联关系,这种关系是递归调用

可以是CascadeType.PERSIST(级联新建)CascadeType.REMOVE(级联删除)CascadeType.REFRESH(级联刷 新)CascadeType.MERGE(级联更新)CascadeType.ALL(全部级联)

fetch 预加载策略和@Basic差不多FetchType.LAZY,FetchType.EAGER

optional 设置关联实体是否必须存在false必须存在 即不是随意的,true关联实体可以不存在即是随意 的。

比如Card(身份证)中的person(人)optional为false意味有身份证就必须有人对应,但是在实体Person中Card的optional为true意味有人不一定要有身份证。

@JoinColumn(name="cardid",referencedColumnName="cid")设置外键,

name该外键的字段名,referencedColumnName外键对应主表的字段

因为card和person是双向关系而在card端已经mappedBy="card"设定card为主表,

所以要在person端的关联项设置外键@JoinColumn

双向一对多与多对一 ,单向一对多与多对一 @OneToMany @ManyToOne 其它的可以参考上面的

双向多对多(实际开发中多对多通常是双向的)

@JoinTable(

name="teacher_student",

joinColumns={@JoinColumn(name="teacher_id",referencedColumnName="tid")},

inverseJoinColumns={@JoinColumn(name="student_id",referencedColumnName="sid")}

)

 

old:

@ManyToMany 注释:表示此类是多对多关系的一边,mappedBy 属性定义了此类为双向关系的维护端,注意:mappedBy 属性的值为此关系的另一端的属性名。
例如,在Student类中有如下方法:
被控方:
            @ManyToMany(fetch = FetchType.LAZY, mappedBy = "students")
public Set<Teacher> getTeachers() {
return teachers;
}
那么这里的“students”就是Teachers的一个属性,通常应该是这样的:
Set<Student> students;
另一端的getStudents方法如下所示:
 主控方:
             @ManyToMany(cascade = CascadeType.PERSIST, fetch = FetchType.LAZY)
@JoinTable(name = "Teacher_Student",
joinColumns = {@JoinColumn(name = "Teacher_ID", referencedColumnName = "teacherid")},
inverseJoinColumns = {@JoinColumn(name = "Student_ID", referencedColumnName ="studentid")})
public Set<Student> getStudents() {
return students;
}
@ManyToMany 注释表示Teacher 是多对多关系的一端。@JoinTable 描述了多对多关系的数据表关系。name 属性指定中间表名称,joinColumns 定义中间表与Teacher 表的外键关系。上面的代码中,中间表Teacher_Student的Teacher_ID 列是Teacher 表的主键列对应的外键列,inverseJoinColumns 属性定义了中间表与另外一端(Student)的外键关系。
 
可以通过上面的定义看到有三个表学生表--老师表--老师学生中间表
以上提到主控方和被控方。。本人不赞同这种写法:
理由是: 1.既然是多对多关系。。为什么还要分主动方和被动方?
              2.为什么需要删除老师后才级联中间表。。。请注意:以上定义方法时,删除学生是无法级联删除中间表的。
正确的写法应该是两边都用主控方的写法:
只是joinColumns和inverseJoinColumns属性的地方互换就可以了
new:(个人观点,,欢迎大家一起来讨论此问题)
总结:
个人的定义:
@ManyToMany(cascade = CascadeType.PERSIST, fetch = FetchType.LAZY)
@JoinTable(name = "Teacher_Student",
joinColumns = {@JoinColumn(name = "Student_ID", referencedColumnName = "studentid")},
inverseJoinColumns = {@JoinColumn(name = "Teacher_ID", referencedColumnName ="teacherid")})
public Set<Teacher> getTeachers() {
return teachers;
}
 
 
 
@ManyToMany(cascade = CascadeType.PERSIST, fetch = FetchType.LAZY)
@JoinTable(name = "Teacher_Student",
joinColumns = {@JoinColumn(name = "Teacher_ID", referencedColumnName = "teacherid")},
inverseJoinColumns = {@JoinColumn(name = "Student_ID", referencedColumnName ="studentid")})
public Set<Student> getStudents() {
return students;
}

 

hibernate调用seeion的工具类:

HibernateUtils类:

复制代码
package utils;import org.hibernate.Session;import org.hibernate.SessionFactory;import org.hibernate.cfg.Configuration;public class HibernateUtils {     private static SessionFactory factory;    static{             try{    Configuration cfg=new Configuration().configure();        factory=cfg.buildSessionFactory();                }catch(Exception e){                    e.printStackTrace();                }          }    public static Session getSession(){        return factory.openSession();    }        public static void closeSession(Session session){        if(session!=null){            if(session.isOpen()){            session.close();            }        }    }        public static SessionFactory getSessionFactory(){        return factory;    }}
复制代码

测试类:测试类中,标红的部分是建立两个表的维护关系必须有的(想想为什么?)如果缺少标红的部分,那么在employee数据表中(下文提到的表)中depart_id的值就为null

复制代码
package test;import java.util.HashSet;import java.util.Set;import com.javabean.Department;import com.javabean.Employee;public class Many2One {    public static void main(String[] args) {        Many2oneDao mvso=new Many2oneDao();                        Employee e1=new Employee();        e1.setName("wanglitao_guodiantong");                Employee e2=new Employee();        e2.setName("wuwenzhao_guodiantong");                Department depart=new Department();        depart.setName("guodiantong_guowang");                e1.setDepart(depart);        e2.setDepart(depart);                Set<Employee> emps=new HashSet<Employee>();        emps.add(e1);        emps.add(e2);        depart.setEmps(emps);                mvso.saveObject(depart);            }}
复制代码

测试结果:

数据库中的表:

多的那一端的表:(employee)

一的那一端的数据表(department表):

结果说明:在employee的表中,depart_id是关联外键。

 

另附一篇比较好的一对多建表实例,作为共同参考:

复制代码
package oneToMany; import java.util.Set; import javax.persistence.*; /* 注意导入时,是导入:import javax.persistence.*;    非导入org.hibernate的相关类:import org.hibernate.annotations.Entity; */ @Entity @Table(name="classes") public class Classes implements Serializable {   @Id   @GeneratedValue(strategy=GenerationType.AUTO)   private int id;   private String name;       @OneToMany(cascade=CascadeType.ALL,mappedBy="classes")      private Set<Student> students; //getter,setter省略 } package oneToMany; import javax.persistence.*; @Entity @Table(name="student") public class Student implements Serializable  {   @Id   @GeneratedValue(strategy=GenerationType.AUTO)   private int sid;       private String sname;       //若有多个cascade,可以是:{CascadeType.PERSIST,CascadeType.MERGE}   @ManyToOne(cascade={CascadeType.ALL})           @JoinColumn(name="classid")     //student类中对应外键的属性:classid   private Classes classes; //getter,setter省略 } public class TestOneToMany { /* CREATE TABLE    student (    --要定义外键!!!!!!!     `sid` double NOT NULL auto_increment,     `classid` double NULL,     `sname` varchar(255) NOT NULL,     PRIMARY KEY    (sid),     INDEX par_ind (classid),     FOREIGN KEY (classid) REFERENCES classes(id) ON DELETE CASCADE ON UPDATE CASCADE ) ENGINE=InnoDB */      public static void main(String[] args) throws SQLException      {     try     {       SessionFactory sf = new AnnotationConfiguration().configure().buildSessionFactory();       Session session=sf.openSession();       Transaction tx=session.beginTransaction();         /*因为mappedBy是定义在classes中,即classes类不负责维护级联关系.即维护者是student.所以,1.要将clsses的数据,赋给student,即用student的setClasses()方法去捆定class数据;2.在进行数据插入/更新session.save()/session.update()时,最后操作的是student.*/      Classes classes=new Classes();       classes.setName("access");               Student st1=new Student();       st1.setSname("jason");       st1.setClasses(classes);       session.save(st1);               Student st2=new Student();       st2.setSname("hwj");       st2.setClasses(classes);       session.save(st2);       tx.commit();/* 输出如下:Hibernate: insert into classes (name) values (?)Hibernate: insert into student (classid, sname) values (?, ?)Hibernate: insert into student (classid, sname) values (?, ?)*//*因为一端维护关系另一端不维护关系的原因,我们必须注意避免在应用中用不维护关系的类(class)建立关系,因为这样建立的关系是不会在数据库中存储的。如上的代码倒过来,则插入时,student的外键值为空.如下:*///      Student st1=new Student(); //      st1.setSname("jason"); //      session.save(st1); //        //      Student st2=new Student(); //      st2.setSname("hwj"); //      session.save(st2); //        //      Set<Student> students=new HashSet<Student>(); //      students.add(st1); //      students.add(st2); //        //      Classes classes=new Classes(); //      classes.setName("access"); //      classes.setStudents(students); //      session.save(classes); /*输出如下:Hibernate: insert into student (classid, sname) values (?, ?)Hibernate: insert into student (classid, sname) values (?, ?)Hibernate: insert into classes (name) values (?)*/    }     catch(HibernateException e)     {       e.printStackTrace();            }   } }