ITPub博客

首页 > 应用开发 > Java > Hibernate 单向/双向 多对多

Hibernate 单向/双向 多对多

Java 作者:爆seed 时间:2016-03-31 11:34:36 0 删除 编辑

Hibernate的多对多从单向和双向来分就是单向多对多和双向多对多两种。


Hibernate的双向多对多


      先来说一下什么是多对多的关系,举个例子,老师和学生,老师有语文老师,数学老师,英语老师等等,学生可以是1班的学生也可以是2班的学生,对于每个学生而言,他有多个老师给他讲课,而对于每一个老师而言,他要授课的学生也有很多,像这样的情况就可以描述成多对多了。即两个表之间,每一个表中的记录都对应另一个表的部分或全部记录的集合,这种情况就是多对多关系,而单向多对多与双向多对多的不同在于单向只是一方的数据模型有另一方的数据集合属性。

      下面就来构建一下老师-学生的数据模型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package com.demo.model.many2many;
 
import java.util.HashSet;
import java.util.Set;
 
public class Teacher {
 
    private Integer id;
    private String tname;
    private String tclass;// 所教课程
 
    Set<Student> students = new HashSet<Student>();
 
    get/set
 
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package com.demo.model.many2many;
 
import java.util.HashSet;
import java.util.Set;
 
public class Student {
 
    private Integer id;
    private String sname;
    private String sclass;// 所属班级
 
    private Set<Teacher> teachers = new HashSet<Teacher>();
     
    get/set
 
}

      数据模型建立完成了,我们来想一下在数据库中应该怎样存储这种关系的数据,首先,像一对多那样去存储这种模型的数据能行吗?我们用图例来看一下:

Student                Teacher

S1 -> t_id = 1            T1

S2 -> t_id = 1            T2

      如上图,老师T1有两个学生S1和S2,从Student端可以用如上的方式以外键列表示,但是若S1还有一个老师T2,而外键列只能指定一个值,因此,多对多的关系仅仅用外键列已经不足以表示了,之前看过一些java视频教程,对这块印象比较深刻。这个时候就需要新增一张表来描述Teacher和Student之间的多对多关系,而保持Student和Teacher的表仅仅是一个普通的表,如下所示:

Student                    Student_Teacher                    Teacher

S1                            S1,T1                                        T1

S2                            S2,T1                                        T2

S3                            S3,T1

                                S1,T2

                                S2,T2

      在Hibernate中,就是采用这样的实现方式,通过两端的表与中间的表设定"多对一"(并不是真正的多对一,只是便于理解)的关系,来间接的实现两端的表的多对多的关系,配置文件如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<hibernate-mapping package="com.demo.model.many2many">
    <class name="Student" table="STUDENT">
        <id name="id" type="java.lang.Integer">
            <column name="ID" />
            <generator class="native" />
        </id>
        <property name="sname" type="java.lang.String">
            <column name="NAME" />
        </property>
        <property name="sclass" type="java.lang.String">
            <column name="SCLASS" />
        </property>
         
        <!-- 映射多对多 -->
        <!-- 
            name:Student类中对应Teacher的集合属性的属性名
            table:多对多的关系描述的表(Hibernate自动生成,只给出表的名字即可)
         -->
        <set name="teachers" table="TEACHER_STUDENT">
            <key>
                <!-- 此column的值是中间表中与Student表的id相对应的字段 -->
                <column name="S_ID" />
            </key>
            <!-- 用many-to-many来描述多对多映射关系 -->
             <!-- 
                 class:Student类中的集合属性terchers所对应的类的类型
                 column:此column的值是中间表中与Teacher表的id相对应的字段
              -->
            <many-to-many class="Teacher" column="T_ID"></many-to-many>
        </set>
    </class>
</hibernate-mapping>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<hibernate-mapping package="com.demo.model.many2many">
    <class name="Teacher" table="TEACHER">
     
        <id name="id" type="java.lang.Integer">
            <column name="ID" />
            <generator class="native" />
        </id>
         
        <property name="tname" type="java.lang.String">
            <column name="NAME" />
        </property>
         
        <property name="tclass" type="java.lang.String">
            <column name="SUBJECT" />
        </property>
         
        <set name="teachers" table="TEACHER_STUDENT" inverse="true">
            <key>
                <column name="T_ID" />
            </key>
            <many-to-many class="Student" column="S_ID"></many-to-many>
        </set>
    </class>
</hibernate-mapping>

执行空测试,结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
Hibernate: 
    drop table if exists STUDENT
Hibernate: 
    drop table if exists TEACHER
Hibernate: 
    drop table if exists TEACHER_STUDENT
Hibernate: 
    create table STUDENT (
        ID integer not null auto_increment,
        NAME varchar(255),
        SCLASS varchar(255),
        primary key (ID)
    )
Hibernate: 
    create table TEACHER (
        ID integer not null auto_increment,
        NAME varchar(255),
        SUBJECT varchar(255),
        primary key (ID)
    )
Hibernate: 
    create table TEACHER_STUDENT (
        S_ID integer not null,
        T_ID integer not null,
        primary key (T_ID, S_ID)
    )
Hibernate: 
    alter table TEACHER_STUDENT 
        add index FK_9g6ot8fdkysxycp5ft05vynto (T_ID), 
        add constraint FK_9g6ot8fdkysxycp5ft05vynto 
        foreign key (T_ID) 
        references TEACHER (ID)
Hibernate: 
    alter table TEACHER_STUDENT 
        add index FK_qimrxgo5ju7xjwsbyqw23xj78 (S_ID), 
        add constraint FK_qimrxgo5ju7xjwsbyqw23xj78 
        foreign key (S_ID) 
        references STUDENT (ID)

      可以看到创建了两个普通的表Teacher和Student,创建了一个中间表Teacher_Student,并且在中间表中有两个联合主键S_ID和T_ID,同时也作为外键列分别对应Student表的id和Teacher表的id,这样就完成了Teacher与Student的多对多关系,下面执行测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
@Test
public void testSave() throws Exception {
    Teacher teacher1 = new Teacher();
    teacher1.setTname("t1");
    teacher1.setTclass("Chinese");
     
    Teacher teacher2 = new Teacher();
    teacher2.setTname("t2");
    teacher2.setTclass("Math");
     
    Student student1 = new Student();
    student1.setSname("s1");
    student1.setSclass("class1");
     
    Student student2 = new Student();
    student2.setSname("s1");
    student2.setSclass("class1");
     
     
    // 设定关联关系
    teacher1.getStudents().add(student1);
    teacher1.getStudents().add(student2);
     
    teacher2.getStudents().add(student1);
    teacher2.getStudents().add(student2);
 
    student1.getTeachers().add(teacher1);
    student1.getTeachers().add(teacher2);
     
    student2.getTeachers().add(teacher1);
    student2.getTeachers().add(teacher2);
     
    // 执行保存操作
    session.save(student1);
    session.save(student2);
     
    session.save(teacher1);
    session.save(teacher2);
}

结果如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
Hibernate: 
    insert 
    into
        STUDENT
        (NAME, SCLASS) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        STUDENT
        (NAME, SCLASS) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        TEACHER
        (NAME, SUBJECT) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        TEACHER
        (NAME, SUBJECT) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        TEACHER_STUDENT
        (S_ID, T_ID) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        TEACHER_STUDENT
        (S_ID, T_ID) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        TEACHER_STUDENT
        (S_ID, T_ID) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        TEACHER_STUDENT
        (S_ID, T_ID) 
    values
        (?, ?)

可以看到总共执行了8条insert语句,即插入数据后,将其中的关联关系插入到中间表中。

其它测试不再赘述


单向多对多


      在双向多对多的基础上,去掉其中一个pojo类的集合属性,相应的配置文件中set集合的相关配置去掉即可,测试结果除了teacher不设定集合属性之外,其它的都相同,故不贴代码和结果,感兴趣的读者可自行测试一下

来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/29917475/viewspace-2072931/ ,如需转载,请注明出处,否则将追究法律责任。

下一篇: java自学的故事
请登录后发表评论 登录
全部评论

注册时间:2014-09-26

  • 博文量
    28
  • 访问量
    34438