zoukankan      html  css  js  c++  java
  • (原创)hibernate 一对多建表实例详解 附上各个注释的含义

    这个是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();        
        } 
      } 
    }
  • 相关阅读:
    同表自更新
    C#数据层添加事务功能
    Mysql 索引 分区 面试题
    Spring 循环依赖
    Zipkin初探 + 与SpringBoot的集成+ 使用HTTP方式传送数据给zipkin server
    Web调优之IBM JDK+liberty(二),原来都是UUID惹得祸
    Web调优之IBM JDK+liberty(一): Jmeter pod里压,50个线程并发测试,调整 -Xms -Xms, Log原来是大问题
    Linux使用jstat命令查看jvm的GC情况
    VM内存回收System.gc()
    prometheus 文档合集
  • 原文地址:https://www.cnblogs.com/zhangshitong/p/5213992.html
Copyright © 2011-2022 走看看