码迷,mamicode.com
首页 > Web开发 > 详细

千山万水之Hibernate(六)——关联映射(一对多)

时间:2015-05-31 15:30:34      阅读:133      评论:0      收藏:0      [点我收藏+]

标签:hibernate   关联   

学习Hibernate的过程中,映射是比较重要的一部分,再说其中哪一种映射比较重要(或可以说是比较常用)呢?那一定很多人会想到一对多关联映射。之所以这样说,是因为在生活中很多这样的实例:班级-学生、企业-员工、文件夹-文件、试卷-题目等。至于生活中为什么会遇到这样大量一对多的情况,似乎是哲学方面的事情了,当然大家可以继续思考,而我们今天主要讨论Hibernate中的一对多。

原理分析

我们仍然拿班级、学生之间的关系做例子:一个班级包含多个学生。相应的实体关系图为:
技术分享
单向关联
由图可知,由于单向的引用,需要Classes来维护班级、学生二者之间的关系,也就是说,当对Student进行增、删、改时,需要Classes来发起之间关系的维护。另一方面,体现到数据库层面上,我们可以想象,怎样可以实现两个表之间的关系呢?这时候我们可以想到之前练习过的多对一的情况。实际上在实现原理方面,这里所说的一对多和多对一是一样的,都需要在多的一端加入一的一端的外键。

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC 
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
    <class name="com.tgb.hibernate.Classes" table="t_classes">
        <id name="id">
            <generator class="native"></generator>
        </id>
        <property name="name" />
        <!--这里采用set标签代表多端,在多端表添加外键列,由一的一端维护此外键关系-->
        <set name="students">
            <key column="classesId" />
            <one-to-many class="com.tgb.hibernate.Student" />
        </set>
    </class>
</hibernate-mapping>

操作示例

测试程序如下:

public void testSave2(){
        Session session = null;
        Transaction tx = null;
        try{
            session = HibernateUtils.getSession();
            tx = session.beginTransaction();

            Student student1 = new Student();
            student1.setName("李雷");
            session.save(student1);

            Student student2 = new Student();
            student2.setName("韩梅梅");
            session.save(student2);

            Set<Student> students = new HashSet<Student>();
            students.add(student1);
            students.add(student2);

            Classes classes = new Classes();
            classes.setName("TGB——9");
            classes.setStudents(students);
            session.save(classes);

            tx.commit();
        }catch(Exception e){
            e.printStackTrace();
            if(tx != null){
                tx.rollback();
            }
        }finally{
            HibernateUtils.closeSession(session);
        }
    }

(说明:程序中调用HibernateUtils的代码实现可参考:千山万水之Hibernate(四)——关联映射(多对一)
执行打印SQL语句如下:

Hibernate: insert into t_students (name) values (?)
Hibernate: insert into t_students (name) values (?)
Hibernate: insert into t_classes (name) values (?)
Hibernate: update t_students set classesId=? where id=?
Hibernate: update t_students set classesId=? where id=?

可以看到,在执行了保存学生、保存班级的SQL语句后,在提交事务时,又发出了更新外键关系的SQL语句,也就是说,在调用session.save(student)的时候,student端不知道classes一端的存在,不能将关联字段添加上。这样出现的问题有两个:

  1. 在提交事务、清理缓存时,会发出额外的update语句,更新关系;
  2. 如果上面的问题还不至于太严重的后果,那在火上浇油一把:
    技术分享
    外键列设置为非空,那将会在执行的过程中报错:
ERROR JDBCExceptionReporter:72 - Field ‘classesId‘ doesn‘t have a default value

问题解决:
设置一对多为双向关联,将维护关系端设置为多端,一端不再维护关系,这样在添加学生的时候就将关系直接保存,而对于一端的加载,不能构成影响。
设置一端配置控制方向上的反转为true,这样只影响数据的存储,不会影响加载。

总结

我们会说,设置关联上的映射关系,通常会根据业务需求来设计,但这里的双向关联,主要是解决一对多单向关联的缺陷,而不是需求驱动的。因此我们的设计也应该灵活,不能严守教条,既要结合具体的业务,也要考虑技术的实现程度。

千山万水之Hibernate(六)——关联映射(一对多)

标签:hibernate   关联   

原文地址:http://blog.csdn.net/lfsfxytgb9_lyg/article/details/46280933

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!