zoukankan      html  css  js  c++  java
  • hibernate 多对多(many-to-many)

    多对多(many-to-many):在操作和性能方面都不太理想,所以多对多的映射使用较少,实际使用中最好转换成一对多的对象模型;hibernate会为我们创建中间关联表,转换成两个一对多。

    1. E-R图


    2. 实体类:

    Teacher实体类如下:

    Java代码  收藏代码
    1. package com.reiyen.hibernate.domain;  
    2.   
    3. import java.util.Set;  
    4.   
    5. public class Teacher {  
    6.   
    7.     private int id;  
    8.     private String name;  
    9.     private Set<Student> students;  
    10.        //setter和getter方法  
    11.   
    12. }  

     Student实体类如下:

    Java代码  收藏代码
    1. package com.reiyen.hibernate.domain;  
    2.   
    3. import java.util.Set;  
    4.   
    5. public class Student {  
    6.   
    7.     private int id;  
    8.     private String name;  
    9.     private Set<Teacher> teachers;  
    10.         //setter和getter方法  
    11.   
    12. }  

     3.映射文件如下:

    Teacher.hbm.xml如下:

    Xml代码  收藏代码
    1. <?xml version="1.0"?>  
    2. <!DOCTYPE hibernate-mapping PUBLIC   
    3.     "-//Hibernate/Hibernate Mapping DTD 3.0//EN"  
    4.     "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">  
    5. <hibernate-mapping package="com.reiyen.hibernate.domain">  
    6.     <class name="Teacher">  
    7.         <id name="id">  
    8.             <generator class="native" />  
    9.         </id>  
    10.         <property name="name" />  
    11.         <!-- 通过table项告诉hibernate中间表的名称 -->  
    12.         <set name="students" table="teacher_student">  
    13.             <!-- 通过key属性告诉hibernate在中间表里面查询teacher_id值相应的teacher记录 -->  
    14.             <key column="teacher_id" />  
    15.             <!-- 通过column项告诉hibernate对student表中查找student_id值相就的studnet记录 -->  
    16.             <many-to-many class="Student" column="student_id" />  
    17.         </set>  
    18.     </class>  
    19. </hibernate-mapping>  

     Student.hbm.xml如下:

    Xml代码  收藏代码
    1. <?xml version="1.0"?>  
    2. <!DOCTYPE hibernate-mapping PUBLIC   
    3.     "-//Hibernate/Hibernate Mapping DTD 3.0//EN"  
    4.     "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">  
    5. <hibernate-mapping package="com.reiyen.hibernate.domain">  
    6.     <class name="Student" >  
    7.         <id name="id" >  
    8.             <generator class="native" />  
    9.         </id>  
    10.         <property name="name" />  
    11.         <set name="teachers" table="teacher_student">  
    12.         <key column="student_id" />  
    13.         <many-to-many class="Teacher" column="teacher_id"/>  
    14.         </set>  
    15.     </class>  
    16. </hibernate-mapping>  

     一定要注意映射文件中<many-to-many class="Teacher" column="teacher_id"/>中class的值,它必须与你另一个关联映射文件中的class属性的name值一致,其实就是与你的实体类的类名一致,如:<many-to-many class="Teacher" column="teacher_id"/>中class的值就不能写成"teacher"。如果写成这样的话,就会抛出如下异常:An association from the table teacher_student refers to an unmapped class: com.reiyen .hibernate.domain.teacher

    4. 测试程序如下:

    Java代码  收藏代码
    1. public class Many2Many {  
    2.     public static void main(String[] args) {  
    3.         add();  
    4.         //query(1);  
    5.     }  
    6.   
    7.     static void query(int id) {  
    8.         Session s = null;  
    9.         Transaction tx = null;  
    10.         try {  
    11.             s = HibernateUtil.getSession();  
    12.             tx = s.beginTransaction();  
    13.             Teacher t = (Teacher) s.get(Teacher.class, id);  
    14.             System.out.println("students:" + t.getStudents().size());  
    15.             tx.commit();  
    16.         } finally {  
    17.             if (s != null)  
    18.                 s.close();  
    19.         }  
    20.     }  
    21.   
    22.     static void add() {  
    23.         Session s = null;  
    24.         Transaction tx = null;  
    25.         try {  
    26.             Set<Teacher> ts = new HashSet<Teacher>();  
    27.   
    28.             Teacher t1 = new Teacher();  
    29.             t1.setName("t1 name");  
    30.             ts.add(t1);  
    31.   
    32.             Teacher t2 = new Teacher();  
    33.             t2.setName("t2 name");  
    34.             ts.add(t2);  
    35.   
    36.             Set<Student> ss = new HashSet<Student>();  
    37.             Student s1 = new Student();  
    38.             s1.setName("s1");  
    39.             ss.add(s1);  
    40.   
    41.             Student s2 = new Student();  
    42.             s2.setName("s2");  
    43.             ss.add(s2);  
    44.   
    45.             t1.setStudents(ss);  //1  
    46.             t2.setStudents(ss);  //1  
    47. //            
    48. //          s1.setTeachers(ts);  //2  
    49. //          s2.setTeachers(ts);  //2  
    50.   
    51.             s = HibernateUtil.getSession();  
    52.             tx = s.beginTransaction();  
    53.             s.save(t1);  
    54.             s.save(t2);  
    55.             s.save(s1);  
    56.             s.save(s2);  
    57.             tx.commit();  
    58.         } finally {  
    59.             if (s != null)  
    60.                 s.close();  
    61.         }  
    62.     }  
    63. }  

     运行此程序后:控制台打印的sql语句如下所示:

    Hibernate: insert into Teacher (name) values (?)
    Hibernate: insert into Teacher (name) values (?)
    Hibernate: insert into Student (name) values (?)
    Hibernate: insert into Student (name) values (?)
    Hibernate: insert into teacher_student (teacher_id, student_id) values (?, ?)
    Hibernate: insert into teacher_student (teacher_id, student_id) values (?, ?)
    Hibernate: insert into teacher_student (teacher_id, student_id) values (?, ?)
    Hibernate: insert into teacher_student (teacher_id, student_id) values (?, ?)

    一共在中间表里面插入了4条记录。

    中间表结构如下所示:

    DROP TABLE IF EXISTS `test`.`teacher_student`;
    CREATE TABLE  `test`.`teacher_student` (
      `teacher_id` int(11) NOT NULL,
      `student_id` int(11) NOT NULL,
      PRIMARY KEY (`student_id`,`teacher_id`),
      KEY `FK2E2EF2DE6C8A2663` (`teacher_id`),
      KEY `FK2E2EF2DE5BEEDBC3` (`student_id`),
      CONSTRAINT `FK2E2EF2DE5BEEDBC3` FOREIGN KEY (`student_id`) REFERENCES `student` (`id`),
      CONSTRAINT `FK2E2EF2DE6C8A2663` FOREIGN KEY (`teacher_id`) REFERENCES `teacher` (`id`)

    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

    表中插入的记录如下所示:

    mysql> select * from teacher_student;
    +------------+------------+
    | teacher_id | student_id |
    +------------+------------+
    |          1 |          1 |
    |          1 |          2 |
    |          2 |          1 |
    |          2 |          2 |
    +------------+------------+
    4 rows in set (0.00 sec)

    程序中注释为1的语句非常重要,它是建立Teacher与Student关联的语句,如果没有这两条语句,虽然程序照样会执行,但是在中间表teacher_student没有任何记录,也就是Teacher与Student之间未关联。

    当然你也可以通过程序中注释为2的语句来建立Teacher与Student之间的关联关系,同样会产生与注释为1的语句的效果。但是你不能在程序中同时出现以上四句程序,否则会抛出异常( PRIMARY KEY (`student_id`,`teacher_id`),所以会出现主键冲突的异常),:

    Hibernate: insert into teacher_student (teacher_id, student_id) values (?, ?)
    Hibernate: insert into teacher_student (teacher_id, student_id) values (?, ?)
    Hibernate: insert into teacher_student (teacher_id, student_id) values (?, ?)
    Hibernate: insert into teacher_student (teacher_id, student_id) values (?, ?)
    Hibernate: insert into teacher_student (student_id, teacher_id) values (?, ?)
    Hibernate: insert into teacher_student (student_id, teacher_id) values (?, ?)
    Hibernate: insert into teacher_student (student_id, teacher_id) values (?, ?)
    Hibernate: insert into teacher_student (student_id, teacher_id) values (?, ?)
    Exception in thread "main" org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update

    解决上面产生异常的办法是设置inverse属性。即在Tearcher一端或Student一端设置inverse="true",即让他们之中的某一方放弃维护关联关系。此时,虽然上面四句程序在测试程序中同时出现了(其实就是在对象模型上相互设置了他们的关联关系),但程序照样能运行正常,因为了在数据库模型上,只会有两句程序生效,也就是没有设置inverse="true"的那一端会去维护关联关系。有关inverse的说细信息,可以参看我的文章hibernate级联(cascade和inverse).

    执行测试程序中的查询测试,控制台打印的信息如下所示:

    Hibernate: select teacher0_.id as id5_0_, teacher0_.name as name5_0_ from Teacher teacher0_ where teacher0_.id=?
    Hibernate: select students0_.teacher_id as teacher1_1_, students0_.student_id as student2_1_, student1_.id as id7_0_, student1_.name as name7_0_ from teacher_student students0_ left outer join Student student1_ on students0_.student_id=student1_.id where students0_.teacher_id=?
    students:2

    从打印出的sql语句可以看出,多对多关系进行查询时,效率是比较低的。
  • 相关阅读:
    表格边框的合并
    solr服务搭建
    JedisClient操作redis 单机版和集群版
    redis集群的搭建
    FastDfs的搭建
    打开与关闭端口
    zookeper分布式搭建1
    zookeper分布式搭建
    Zookeeper的安装
    Linux下Jdk的安装
  • 原文地址:https://www.cnblogs.com/baobeiqi-e/p/9884826.html
Copyright © 2011-2022 走看看