(原创)hibernate 一对多建表实例详解 附上各个注释的含义-程序员宅基地

技术标签: java  数据库  

这个是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();        
    } 
  } 
}

 

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

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_30664615/article/details/95650759

智能推荐

Flutter中2个库的类名冲突解决方法_flutter 类冲突-程序员宅基地

文章浏览阅读2.7w次。Flutter中2个库的类名冲突解决方法例如,我们在使用国际化时,会给组件(如,日历组件),设置一个本地属性来显示当地语言:locale: Locale("zh")上例中,显示中文。当我们引用第三方库 date_format 来格式化日期时,由于 date_format 库中,也包含了 Locale 组件,这时,就会报错。[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lUi4kEip-1609149717960)(evernotecid://6FE75482-5_flutter 类冲突

新技术加速隐私暴露,如何应对?-程序员宅基地

文章浏览阅读9.3k次。新技术加速隐私暴露,如何应对?(一)原创数据玩家一个数据玩家的自我修养2019-10-09收录于话题#新技术与隐私保护8个点击上方蓝字关注数据玩家 正文约4000字,读完需11分钟序最近的大数据行业风声鹤唳,多家大数据服务头部企业、贷超、催收公司被查,引发行业地震,未被牵连的企业纷纷自查,其他头部公司黑稿和纠纷频出。从业者如惊弓之鸟,人人自危;普通用户纷纷叫好,同时引发对隐私保护的担忧和强监管诉求。此刻我又想...

elementUI el-dialog自适应高度,仅body内容部分滚动_el-dialog高度自适应-程序员宅基地

文章浏览阅读1.5w次,点赞5次,收藏11次。定义样式如下:.abow_dialog { display: flex; justify-content: center; align-items: Center; overflow: hidden; .el-dialog { margin: 0 auto !important; height: 90%; ..._el-dialog高度自适应

C++实现简单五子棋游戏_c++五子棋-程序员宅基地

文章浏览阅读6.5w次,点赞106次,收藏633次。  五子棋是世界智力运动会竞技项目之一,是一种两人对弈的纯策略型棋类游戏,是世界智力运动会竞技项目之一,通常双方分别使用黑白两色的棋子,下在棋盘直线与横线的交叉点上,先形成5子连线者获胜。 规则(1)对局双方各执一色棋子。 (2)空棋盘开局。 (3)黑先、白后,交替下子,每次只能下一子。 (4)棋子下在棋盘的空白点上,棋子下定后,不得向其它点移动,不得从棋盘上拿掉或拿起另落别处..._c++五子棋

python箭头符号怎么打_python – 用箭头标记matplotlib直方图bin-程序员宅基地

文章浏览阅读1.2k次。您可以使用注释添加箭头:import pandas as pdimport matplotlib.pyplot as plt#import seaborn as snsimport numpy as npfig,ax = plt.subplots()series = pd.Series(np.random.normal(0,1000))series.plot(kind='hist',bins=50..._python右箭头怎么打出来

python数据滤波_python实现滤波-程序员宅基地

文章浏览阅读1.1k次。Python+OpenCV基础教程2:平滑图像学习模糊/平滑图像,消除噪点。图片等可到源码处下载。1、目标2、教程滤波与模糊推荐大家先阅读:番外篇:卷积基础(图片边框),有助于理解卷积和滤波的概念。关于滤波和模糊,很多人分不清,我来给大家理理(虽说如此,我后面也会混着用,,ԾㅂԾ,,):它们都属于卷积,不同滤波方法之间只是卷积...文章初商2019-08-04484浏览量深度学习第18讲:CNN经..._python 血氧滤波

随便推点

多任务学习:Transformer based MultiHead Self-Attention Networks_transformer多任务-程序员宅基地

文章浏览阅读2.4k次。孤岛模型被证明是单词生成模型的理想基础。马尔可夫链蒙特卡洛(MCMC)方法,在统计物理和材料科学领域均产生了重大影响。同样,在自然语言处理领域,深度学习技术也扮演着至关重要的角色,包括基于RNN、CNN、LSTM等的预训练语言模型、神经机器翻译、条件随机场、长短时记忆网络等,这些模型都取得了显著的效果。而在医疗问答系统中,自然语言理解和机器阅读理解组件的实现也逐渐成为关键任务,如何将两种学习模型结合起来,并对医疗数据进行有效处理,是关键之处。_transformer多任务

spring boot整合mybatis+mybatis-plus-程序员宅基地

文章浏览阅读326次。Spring boot对于我来说是一个刚接触的新东西,学习过程中,发现这东西还是很容易上手的,Spring boot没配置时会默认使用Spring data jpa,这东西可以说一个极简洁的工具,可是我还是比较喜欢用mybatis,工具是没有最好的,只有这合适自己的。说到mybatis,最近有一个很好用的工具--------mybatis-Plus(官网),现在更新的版本是2.1.2..._mybatis plus connection-properties

腾讯面试 知乎,Python常用模块 之 jsonpath模块—,Python开发实战-程序员宅基地

文章浏览阅读719次,点赞22次,收藏12次。Python崛起并且风靡,因为优点多、应用领域广、被大牛们认可。学习 Python 门槛很低,但它的晋级路线很多,通过它你能进入机器学习、数据挖掘、大数据,CS等更加高级的领域。Python可以做网络应用,可以做科学计算,数据分析,可以做网络爬虫,可以做机器学习、自然语言处理、可以写游戏、可以做桌面应用…Python可以做的很多,你需要学好基础,再选择明确的方向。这里给大家分享一份全套的 Python 学习资料,给那些想学习 Python 的小伙伴们一点帮助!

那些“不顾一切”要搞开源的人,现在怎样了?-程序员宅基地

文章浏览阅读1.6k次。开源,不好做,无论是在过去还是现在。过去 20 年间,无数顶尖技术人“冲锋陷阵”,打开了中国开源的大门。还记得彼时“中国 Linux 第一人”宫敏博士用手提肩背,将 20 盒装有 80G ..._开源创业 潜力股 英雄帖,在 10+ 投资人面前秀出你的实力

Linux USB 详解_usbdev_do_ioctl-程序员宅基地

文章浏览阅读1w次。To understand all the Linux-USB framework, youll use these resources: * This source code. "make pdfdocs", "usb.pdf" for host side "gadget.pdf" for peripheral side * The_usbdev_do_ioctl

推荐开源项目:LogMe - 实时日志管理和分析工具-程序员宅基地

文章浏览阅读302次,点赞3次,收藏6次。推荐开源项目:LogMe - 实时日志管理和分析工具项目地址:https://gitcode.com/BNMetrics/logme项目简介LogMe 是一个强大且易用的日志管理与分析平台,它提供了实时查看、搜索、过滤和聚合日志的能力,帮助开发者和运维人员快速定位问题,优化系统性能。这个开源项目旨在简化日志处理流程,让复杂的数据变得简单易读。技术分析架构设计LogMe 基于微服务架构,...