Hibernate(三)

级联操作
1、只能通过班级联系到学生,不能通过学生联系到班级
2、如果涉及到关系操作,只能从班级出发维护关系
3、只要涉及到维护关系就会发出update语句
4、所以一对多,一对一方维护关系效率不高
5、级联操作:save-update

一对多的情况
结构

public class Student implements Serializable{
    private Long sid;
    private String name;
    private Classes classes;

在Student.hbm.xml文件中

    <many-to-one name="classes" class="cn.itcast.sh08.hibernate.domain.Classes" column="cid"></many-to-one>

保存学生,并且建立和班级的关系

@Test
    public void testSaveStudent(){
        Session session = sessionFactory.getCurrentSession();
        Transaction transaction = session.beginTransaction();
        /**
         * 新创建一个学生
         */
        Student student = new Student();//临时状态的对象
        student.setName("adsf");
        //提取cid为7的班级
        Classes classes = (Classes)session.get(Classes.class,7L);
        student.setClasses(classes);
        session.save(student);
        transaction.commit();
    }

学生转移班级

@Test
    public void testTransform(){
        Session session = sessionFactory.getCurrentSession();
        Transaction transaction = session.beginTransaction();

        Classes classes = (Classes)session.get(Classes.class, 3L);
        Student student = (Student)session.get(Student.class, 1L);

        student.setClasses(classes);
        transaction.commit();
    }

保存一些学生,建立关系

@Test
    public void testSaveStudent_R(){
        Session session = sessionFactory.getCurrentSession();
        Transaction transaction = session.beginTransaction();

        Student student1 = new Student();
        student1.setName("aaa");
        Student student2 = new Student();
        student2.setName("bbb");

        Classes classes=(Classes)session.get(Classes.class, 3L);
        student1.setClasses(classes);
        student2.setClasses(classes);

        session.save(student1);
        session.save(student2);
        transaction.commit();
    }

1、一对多如果多的一方维护关系,不会发出update语句
2、一般情况下,一对多,多的一方维护关系效率比较高
3、在一般情况下,classes.hbm.xml文件中的set元素中的inverse属性一般设置为true
4、如果上述的配置的inverse设置为false,那么只要更新了关系,只要在代码端建立了classes与student之间的关系,session只要操作classes,就会发出更新外键的sql语句,这样效率比较低

多对多
持久化类和映射文件

public class Course implements Serializable{
    private Long cid;
    private String name;
    private Set<Student> students;

public class Student implements Serializable{
    private Long sid;
    private String name;
    private Set<Course> courses;

在Student.hbm.xml文件中

<set name="courses" table="student_course" cascade="save-update">
            <!-- 
                外键
                   sid为student_course表中的一个外键
             -->
            <key>
                <column name="sid"></column>
            </key>
            <!-- 
                column
                      外键
             -->
            <many-to-many class="cn.itcast.sh08.hibernate.domain.Course" column="cid"></many-to-many>
        </set>

在Course.hbm.xml文件中

<set name="students" table="student_course">
            <!-- 
                外键
             -->
            <key>
                <column name="cid"></column>
            </key>
            <many-to-many class="cn.itcast.sh08.hibernate.domain.Student" column="sid"></many-to-many>
        </set>

考虑问题
1、多对多谁维护关系效率比较高
谁维护关系,都得修改第三张表,所以谁维护关系效率都一样。
2、关于关系:
a)当建立关系的时候,相当于插入一行数据
b)当解除关系的时候,相当于删除一行数据
c)当重新建立关系的时候,先删除后增加

/**
     * 保存学生的同时保存课程
     */
    @Test
    public void testSaveStudent_Cascade_Save_Course(){
        Session session = sessionFactory.getCurrentSession();
        Transaction transaction = session.beginTransaction();
        /**
         * 新建一个学生
         */
        Student student = new Student();
        student.setName("aa");
        /**
         * 新建一个课程
         */
        Course course = new Course();
        course.setName("java基础");
        /**
         * 建立学生和课程之间的关系
         */
        Set<Course> courses = new HashSet<Course>();
        courses.add(course);
        student.setCourses(courses);
        session.save(student);
        transaction.commit();
    }

说明:
当执行session.flush的时候,hibernate内部的工作为:
1、保存学生
2、因为有cascade属性,所以要检查student中的set集合从而保存课程。
因为inverse属性没有写,所以默认值为false,维护关系,所以要发出维护关系的sql语句。

/**
     * 已知一个课程,已知一个学生,建立该学生和该课程之间的关系
     *      建立sid为2的学生和cid为1的课程之间的关系
     */
    @Test
    public void testBuildR(){
        Session session = sessionFactory.getCurrentSession();
        Transaction transaction = session.beginTransaction();
        //提取sid为2的学生
        Student student = (Student)session.get(Student.class, 2L);
        //提取cid为1的课程
        Course course = (Course)session.get(Course.class, 1L);
        student.getCourses().add(course);//获取到sid为2的所有的课程,在此基础上加一门课程
        //course.getStudents().add(student);
        transaction.commit();
    }
/**
     * 一个学生从一个课程转移到另外一个课程
     *  学生1从课程1转移到课程2
     */
    @Test
    public void testTransform(){
        Session session = sessionFactory.getCurrentSession();
        Transaction transaction = session.beginTransaction();
        //获取学生1,课程1,课程2
        Student student = (Student)session.get(Student.class, 1L);
        Course course1 = (Course)session.get(Course.class, 1L);
        Course course2 = (Course)session.get(Course.class, 2L);
        student.getCourses().remove(course1);//解除该学生与课程1之间的关系   删除关系的操作
        student.getCourses().add(course2);//建立该学生与课程2之间的关系           增加关系的操作
        transaction.commit();
    }
/**
     * 解除一个课程和该课程所有的学生之间的关系
     *   解除cid为2的课程和该课程所有的学生之间的关系
     */
    @Test
    public void testRelease_R(){
        Session session = sessionFactory.getCurrentSession();
        Transaction transaction = session.beginTransaction();
        //获取cid为2的课程
        Course course = (Course)session.get(Course.class, 2L);
        //把课程中的学生设置为null
        course.setStudents(null);
        transaction.commit();
    }
/**
     * 删除一个课程
     */
    @Test
    public void testDeleteCourse(){
        Session session = sessionFactory.getCurrentSession();
        Transaction transaction = session.beginTransaction();
        Course course = (Course)session.get(Course.class, 1L);
        session.delete(course);
        transaction.commit();
    }

总结
1、谁维护关系效率都一样
2、客户端的代码怎么写看发出的sql语句越少效率越高
3、关系的维护
建立关系:在第三张表中增加一行记录
解除关系:在第三张表中删除一行记录
重新建立关系:先删除后增加

一对一
在Student.hbm.xml文件中

<many-to-one name="classes" unique="true" column="cid"></many-to-one>

说明cid在student表中的值是唯一的

懒加载(延迟加载)
用到该数据的时候才要向数据库要数据

类的延迟加载

/**
     * 类的延迟加载
     */
    @Test
    public void testClassLazy(){
        Session session = sessionFactory.getCurrentSession();
        Transaction transaction = session.beginTransaction();
        Classes classes = (Classes)session.load(Classes.class,1L);
        //System.out.println(classes.getName());
        transaction.commit();
    }

说明:
由session.load方法产生的classes为代理对象,似乎由javasist包产生的,属性为null。
上述的代码并不发出sql语句当执行输出语句时才要发出sql语句

Classes.hbm.xml文件中进行如下的设置:

<class name="zx.hibernate.domain.Classes" lazy="true">
/**
     * 集合的延迟加载
     */
    @Test
    public void testSetLazy(){
        /**
         * 加载cid为1的班级的所有的学生
         */
        Session session = sessionFactory.getCurrentSession();
        Transaction transaction = session.beginTransaction();
        Classes classes = (Classes)session.get(Classes.class, 1L);
        Set<Student> students = classes.getStudents();
        for(Student student:students){
            System.out.println(student.getName());
        }
        transaction.commit();
    }

说明:在for循环的时候才发出加载集合的sql语句,这样的情况为集合的延迟加载

如果把set集合的延迟加载变成false,则在加载classes的时候,同时加载student

/**
     * 集合的延迟加载Extra
     */
    @Test
    public void testSetLazy_Extra(){
        /**
         * 加载cid为1的班级的所有的学生
         */
        Session session = sessionFactory.getCurrentSession();
        Transaction transaction = session.beginTransaction();
        Classes classes = (Classes)session.get(Classes.class, 1L);
        Set<Student> students = classes.getStudents();
        System.out.println(students.size());
        transaction.commit();
    }

因为把lazy设置成了extra,在客户端的代码只需要学生的数量,所以只发生了count的sql语句,为更进一步的延迟加载

Manytoone的延迟加载
说明:
默认值为no-proxy,为延迟加载。但是多对一的延迟加载对于效率的提高有限,因为根据多的一方加载一的一方就加载一个对象,所以保持默认就好。

总结
1、懒加载是通过控制sql语句的发出时间来提高效率的
2、但映射文件只有一份,不能随便改
3、懒加载只不过是hibernate给程序员提供的一种优化途径而已

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值