zoukankan      html  css  js  c++  java
  • hibernate关联映射

    本文可作为北京尚学堂马士兵hibernate课程的学习笔记。


    hibernate的映射,主要分为一对一,一对多,多对一,多对多,同一时候还要单向与双向的差别。


    OK,不要纠结于名字,我们開始看样例。


    一对一单向

    老公是一个实体,老婆也是一个实体。
    一个老公仅仅有一个老婆,同一时候一个老婆也仅仅有一个老公。
    上面的关系就叫做一对一。


    什么叫单向呢。
    看代码:

    package com.bjsxt.hibernate;
    
    @Entity
    public class Husband {
        private int id;
        private String name;
        private Wife wife;
        
        @Id
        @GeneratedValue
        public int getId() {
            return id;
        }
        
        @OneToOne
        @JoinColumn(name="wifeId")
        public Wife getWife() {
            return wife;
        }
        //省略get set
    }
    
    
    package com.bjsxt.hibernate;
    
    @Entity
    public class Wife {
        private int id;
        private String name;
        
        @Id
        @GeneratedValue
        public int getId() {
            return id;
        }
        //省略get set
    }


    看上面的代码,老公里面有老婆的引用,而老婆里面并没有老婆的引用。
    换句话说在代码层次上,依据老公我们能够获得他的老婆,可是依据老婆无法获得老公。(这就是单向)

    我们看看它执行的代码
    package com.bjsxt.hibernate;
    
    import org.hibernate.cfg.AnnotationConfiguration;
    import org.hibernate.tool.hbm2ddl.SchemaExport;
    
    public class Test {
        public static void main(String[] args) {
            new SchemaExport(new AnnotationConfiguration().configure()).create(false, true);    
        }
    }
    在hibernate的配置文件中
    加上
    <property name="hbm2ddl.auto">update</property>
    结果
    19:41:04,229 DEBUG org.hibernate.tool.hbm2ddl.SchemaExport:377 -
        create table Husband (
            id integer not null auto_increment,
            name varchar(255),
            wifeId integer,
            primary key (id)
        )
    19:41:04,549 DEBUG org.hibernate.tool.hbm2ddl.SchemaExport:377 -
        create table Wife (
            id integer not null auto_increment,
            name varchar(255),
            primary key (id)
        )
    19:41:04,880 DEBUG org.hibernate.tool.hbm2ddl.SchemaExport:377 -
        alter table Husband
            add index FKAEEA401B109E78ED (wifeId),
            add constraint FKAEEA401B109E78ED
            foreign key (wifeId)
            references Wife (id)

    先给husband加了一个字段,wifeId,然后让他作为外键引用wife表的id字段。
    大家能够看到,@JoinColumn(name="wifeId")这个元标签指示了husband表内部那那个关联字段的名字。
    假设没有这个元标签呢?
    那么关联字段就是是:wife_id。

    即tableName_primarykey。
    假设把 @onetoone写到Wife里(husband里没有onotoone的标签),那么我们就能从wife获得husband了(在代码层次)。



    一对一双向

    假设我既想从husband里取得wife,也想从wife里取得husband。那咋办?


    把husband里的标签复制一遍就OK了嘛。


    package com.bjsxt.hibernate;
    
    @Entity
    public class Wife {
        private int id;
        private String name;
        private Husband husband;
        
        @Id
        @GeneratedValue
        public int getId() {
            return id;
        }
        
        @OneToOne
        @JoinColumn(name="husbandId")
        public Husband getHusband() {
            return husband;
        }
    
    }

    OK,上面的代码里,wife也能够取到husband了。
    我们看看hibernate生成的sql
    create table Husband (
            id integer not null auto_increment,
            name varchar(255),
            wifeId integer,
            primary key (id)
        )
    19:53:20,487 DEBUG org.hibernate.tool.hbm2ddl.SchemaExport:377 -
        create table Wife (
            id integer not null auto_increment,
            name varchar(255),
            husbandId integer,
            primary key (id)
        )
    19:53:20,824 DEBUG org.hibernate.tool.hbm2ddl.SchemaExport:377 -
        alter table Husband
            add index FKAEEA401B109E78ED (wifeId),
            add constraint FKAEEA401B109E78ED
            foreign key (wifeId)
            references Wife (id)
    19:53:21,421 DEBUG org.hibernate.tool.hbm2ddl.SchemaExport:377 -
        alter table Wife
            add index FK292331CE01A6E1 (husbandId),
            add constraint FK292331CE01A6E1
            foreign key (husbandId)
            references Husband (id)
    看见了吧,wife里面有外键,husband里面也有外键!
    这不是冗余了嘛。
    把wife类改成以下的样子
        @OneToOne(mappedBy="wife")
        public Husband getHusband() {
            return husband;
        }
    这个mappedBy的意思是说,我(Wife这个类)和husband这个类是一对一关联的,可是关联的外键由husband类的getWife方法控制。
    执行一下。
    20:03:18,611 DEBUG org.hibernate.tool.hbm2ddl.SchemaExport:377 -
        create table Husband (
            id integer not null auto_increment,
            name varchar(255),
            wifeId integer,
            primary key (id)
        )
    20:03:18,618 ERROR org.hibernate.tool.hbm2ddl.SchemaExport:348 - Unsuccessful: create table Husband (id integer not null auto_increment, name varchar(255), wifeId integer, primary key (id))
    20:03:18,618 ERROR org.hibernate.tool.hbm2ddl.SchemaExport:349 - Table 'husband' already exists
    20:03:18,619 DEBUG org.hibernate.tool.hbm2ddl.SchemaExport:377 -
        create table Wife (
            id integer not null auto_increment,
            name varchar(255),
            primary key (id)
        )
    20:03:18,933 DEBUG org.hibernate.tool.hbm2ddl.SchemaExport:377 -
        alter table Husband
            add index FKAEEA401B109E78ED (wifeId),
            add constraint FKAEEA401B109E78ED
            foreign key (wifeId)
            references Wife (id)
    数据库里,wife表里没有外键了。
    可是,在代码层次我们依旧能够从Wife类里获得Husband。



    注意上面的 @OneToOne(mappedBy="wife")
    仅仅有是双向关联,最好就都写上mappedBy,两张表有一个外键就够了。




    多对一单向关联

    每个人都会有非常多个梦想,可是每个梦想仅仅属于某一个详细的人。
    我们先无论java代码上怎样实现,在数据库里。
    上面的两张表,一个是person,里面就是id,name
    再就是dream表,一个id,一个description。
    那么它们的外键放在哪张表里呢?


    放在dream里,换言之,dream表里有一个字段叫personId。


    这个的原因,不用解释。


    全部一对多,多对一的关系,在数据库里,外键都是放在多的一方里的。
    为什么。自己想。




    看代码

    package com.bjsxt.hibernate;
    
    @Entity
    public class Dream {
        private int id;
        private String description;    
        private Person person;
        
        @Id
        @GeneratedValue
        public int getId() {
            return id;
        }
        @ManyToOne
        @JoinColumn(name="personId")
        public Person getPerson() {
            return person;
        }
        //省略get set
    }
    
    
    package com.bjsxt.hibernate;
    
    @Entity
    public class Person {
        private int id;
        private String name;
        
        @Id
        @GeneratedValue
        public int getId() {
            return id;
        }    
        //省略get set
    }
    从代码层次上看"多对一单向"
    就是我能够从多的一方(dream)里获得一的那一方(person)。


    由于是单向,所以不能从person获得他全部的dream。
    OK,生成的表里,dream里有personid。

    20:20:21,970 DEBUG org.hibernate.tool.hbm2ddl.SchemaExport:377 -
        create table Dream (
            id integer not null auto_increment,
            description varchar(255),
            personId integer,
            primary key (id)
        )
    20:20:22,264 DEBUG org.hibernate.tool.hbm2ddl.SchemaExport:377 -
        create table Person (
            id integer not null auto_increment,
            name varchar(255),
            primary key (id)
        )
    20:20:22,765 DEBUG org.hibernate.tool.hbm2ddl.SchemaExport:377 -
        alter table Dream
            add index FK3F397E3C1409475 (personId),
            add constraint FK3F397E3C1409475
            foreign key (personId)
            references Person (id)



    一对多单向关联

    还是人与梦想的样例。
    我想在代码层次,通过人获得他的全部的梦想,怎么办?
    首先在dream类里删除person的引用
    package com.bjsxt.hibernate;
    
    @Entity
    public class Person {
        private int id;
        private String name;
        private Set<Dream> dreams=new HashSet<>();
        
        @Id
        @GeneratedValue
        public int getId() {
            return id;
        }
    
        @OneToMany
        @JoinColumn(name="psrsonId")
        public Set<Dream> getDreams() {
            return dreams;
        }    
    }


    OK,大功告成。


    建表语句和上面的一样。
    装dream的集合类为什么是set?

    list行不,map行不?
    都行。
    可是记着,数据库里面的记录是无序且不相等的。
    你说用哪个?




    无论是oneToMany还是manyToMany,加的 @JoinColumn(name="abc")
    都是在多的一方增加指向少的一方的名叫abc的外键。




    一对多双向关联(多对一双向关联)

    以下的样例,大家猜也猜到了,我既想从dream获得它所属的person,还想从person获得他全部的dream。
    我们看代码:
    package com.bjsxt.hibernate;
    
    @Entity
    public class Dream {
        private int id;
        private String description;
        
        private Person person;
        
        @Id
        @GeneratedValue
        public int getId() {
            return id;
        }
    
        public void setId(int id) {
            this.id = id;
        }
    
        @ManyToOne
        @JoinColumn(name="personId")
        public Person getPerson() {
            return person;
        }
    }
    
    package com.bjsxt.hibernate;
    
    @Entity
    public class Person {
        private int id;
        private String name;
        private Set<Dream> dreams=new HashSet<>();
    
        @Id
        @GeneratedValue
        public int getId() {
            return id;
        }
    
        @OneToMany(mappedBy="person")
        public Set<Dream> getDreams() {
            return dreams;
        }
    }
    ok,我们能够在代码里,通过dream获得person也能够通过person获得dream



    多对多单向关联

    样例非常easy,一个老师能够教多个学生,一个学生能够被多个老师教。
    单向是说,要么老师能"知道"自己的学生,要么学生能知道自己的老师。
    我们先看老师能"知道"自己学生的代码。

    package com.bjsxt.hibernate;
    
    @Entity
    public class Student {
        private int id;
        private String name;
        
        @Id
        @GeneratedValue
        public int getId() {
            return id;
        }
    }
    OK,学生里面没有老师的引用。
    package com.bjsxt.hibernate;
    
    @Entity
    public class Teacher {
        private int id;
        private String name;
        private Set<Student> students = new HashSet<Student>();
        @Id
        @GeneratedValue
        public int getId() {
            return id;
        }
        
        @ManyToMany
        @JoinTable(name="t_s",
            joinColumns={@JoinColumn(name="teacher_id")},
            inverseJoinColumns={@JoinColumn(name="student_id")}
            )
        public Set<Student> getStudents() {
            return students;
        }
    }
    看结果:
    21:10:35,854 DEBUG org.hibernate.tool.hbm2ddl.SchemaExport:377 -
        create table Student (
            id integer not null auto_increment,
            name varchar(255),
            primary key (id)
        )
    21:10:36,192 DEBUG org.hibernate.tool.hbm2ddl.SchemaExport:377 -
        create table Teacher (
            id integer not null auto_increment,
            name varchar(255),
            primary key (id)
        )
    21:10:36,643 DEBUG org.hibernate.tool.hbm2ddl.SchemaExport:377 -
        create table t_s (
            teacher_id integer not null,
            student_id integer not null,
            primary key (teacher_id, student_id)
        )
    21:10:36,947 DEBUG org.hibernate.tool.hbm2ddl.SchemaExport:377 -
        alter table t_s
            add index FK1BF68BF77BA8A (teacher_id),
            add constraint FK1BF68BF77BA8A
            foreign key (teacher_id)
            references Teacher (id)
    21:10:37,588 DEBUG org.hibernate.tool.hbm2ddl.SchemaExport:377 -
        alter table t_s
            add index FK1BF68AEDC6FEA (student_id),
            add constraint FK1BF68AEDC6FEA
            foreign key (student_id)
            references Student (id)
    21:10:38,263  INFO org.hibernate.tool.hbm2ddl.SchemaExport:268 - schema export complete
    

    我们看看生成的t_s表和里面的字段名称应该就能明确 @JoinTable的作用
    它就是在manytomany时,指定第三张表的表名和字段。


    joinColumns 指的是指向自己这个类的字段名
    inverseJoinColumns inverse是反向的意思 所以这个标签就是运行另外那个类的字段
    假设没有 @JoinTable这个标签,会是什么样子呢?大家自己试一下。
    另外,上面的代码是从老师到学生,大家再试试从学生到老师。


    多对多双向关联

    在上面的样例里
    改变student,给它加上teacher的引用。

    package com.bjsxt.hibernate;
    
    
    @Entity
    public class Student {
        private int id;
        private String name;
        private Set<Teacher> teachers=new HashSet<>();
        
        @Id
        @GeneratedValue
        public int getId() {
            return id;
        }
        
        //记着 双向的时候 就加上mappedBy
        @ManyToMany(mappedBy="students")
        public Set<Teacher> getTeachers() {
            return teachers;
        }
    
    }


    glt likes dlf

    dlf likes glt

    oneToOne



  • 相关阅读:
    盒子垂直水平居中
    Sahi (2) —— https/SSL配置(102 Tutorial)
    Sahi (1) —— 快速入门(101 Tutorial)
    组织分析(1)——介绍
    Java Servlet (1) —— Filter过滤请求与响应
    CAS (8) —— Mac下配置CAS到JBoss EAP 6.4(6.x)的Standalone模式(服务端)
    JBoss Wildfly (1) —— 7.2.0.Final编译
    CAS (7) —— Mac下配置CAS 4.x的JPATicketRegistry(服务端)
    CAS (6) —— Nginx代理模式下浏览器访问CAS服务器网络顺序图详解
    CAS (5) —— Nginx代理模式下浏览器访问CAS服务器配置详解
  • 原文地址:https://www.cnblogs.com/brucemengbm/p/6946627.html
Copyright © 2011-2022 走看看