美文网首页
hibernate 多对多

hibernate 多对多

作者: siriusing | 来源:发表于2017-10-30 14:32 被阅读18次

0.0 参数

class.catalog="指定数据库的,建议删掉"

set.inverse:是否要放弃维护外键关系
    true:  放弃维护主键
    false: 我
    default value:false
set.cascade:是否需要级联操作 (5个)
      save-update:A保存,同时保存B
      delete:删除A,同时删除B,AB都不存在
      delete-orphan:孤儿删除,解除关系,同时将B删除,A存在的。
      如果需要配置多项,使用逗号分隔。<set cascade="save-update,delete">

      all : save-update 和 delete 整合
      all-delete-orphan : 三个整合

   容器<set> 提供两个属性:fetch、lazy
    fetch:确定使用sql格式
    lazy:关联对象是否延迟。
   fetch:join、select、subselect
    join:底层使用迫切左外连接
    select:使用多个select语句(默认值)
    subselect:使用子查询
   lazy:false、true、extra
    false:立即
    true:延迟(默认值)
    extra:极其懒惰


1.0 简单多对多(双向多对多)


<hibernate-mapping package="cc.sirius.bean">
    <class name="对应类名" table="表名">
        <id name="主键">
            <generator class="主键生成策略"></generator>
        </id>
        <property name="类对象的对应属性"></property>
        <set name="对应set属性" table="维护关联关系的表名">
            <key column="在维护关系那里的自己的主键"></key>
            <many-to-many  class="关联类" column="关联类的关联id"></many-to-many>
        </set>
    </class>
</hibernate-mapping>
image.png
<?xml version="1.0" encoding="UTF-8"?>
<!-- Student.hbm.xml -->
<!DOCTYPE hibernate-mapping PUBLIC 
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="cc.sirius.bean">
    <class name="Student" table="t_student"  >
    
        <id name="sid" column="sid">
            <generator class="native"></generator>
        </id>
        <property name="name"></property>
        <property name="sex"></property>

        <set name="courses" table="t_student_course" >
            <key column="sid" not-null="true" ></key>
            <many-to-many  class="Course" column="cid" ></many-to-many>
        </set>

    </class>

</hibernate-mapping>




<?xml version="1.0" encoding="UTF-8"?>
<!-- Course.hbm.xml -->
<!DOCTYPE hibernate-mapping PUBLIC 
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="cc.sirius.bean">
    <class name="Course" table="t_course">
        
        <id name="cid" column="cid">
            <generator class="native"></generator>
        </id>
        <property name="cname"></property>
    
        <set name="students" table="t_student_course" >
            <key column="cid" not-null="true"></key>
            <many-to-many class="Student" column="sid"></many-to-many>
        </set>
    
    </class>

</hibernate-mapping>

1.1添加


@Test
    public void add() {

        Session session = HibernateUtils.openSession();
        session.beginTransaction();
        // -----------------------------------------------------
        Student s1 = new Student();
        s1.setName("旺旺");
        s1.setSex("男");

        Student s2 = new Student();
        s2.setName("小董");
        s2.setSex("男");

        Course c1 = new Course();
        c1.setCname("语文");
        Course c2 = new Course();
        c2.setCname("数学");

        // 维护关系
        s1.getCourses().add(c1);
        s1.getCourses().add(c2);

        s2.getCourses().add(c1);
        s2.getCourses().add(c2);

        session.save(c1);
        session.save(c2);
        session.save(s1);
        session.save(s2);

        // ------------------------------------------------------
        session.getTransaction().commit();
        session.close();
    }

输出:
Hibernate: 
    insert 
    into
        t_course
        (cname) 
    values
        (?)
Hibernate: 
    insert 
    into
        t_course
        (cname) 
    values
        (?)
Hibernate: 
    insert 
    into
        t_student
        (name, sex) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        t_student
        (name, sex) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        t_student_course
        (sid, cid) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        t_student_course
        (sid, cid) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        t_student_course
        (sid, cid) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        t_student_course
        (sid, cid) 
    values
        (?, ?)

1.2 更新

    @Test
    public void update() {
        Session session = HibernateUtils.openSession();
        session.beginTransaction();
        // -----------------------------------------------------
            Student student01 = (Student) session.get(Student.class, 1);
            
            Iterator<Course> it = student01.getCourses().iterator();
            int i=0;
            while(it.hasNext()){
                Course c = it.next();
                c.setCname("小白"+i++);
            }
            
        // ------------------------------------------------------
        session.getTransaction().commit();
        session.close();
        
    }
Hibernate: 
    select
        student0_.sid as sid2_0_,
        student0_.name as name2_0_,
        student0_.sex as sex2_0_ 
    from
        t_student student0_ 
    where
        student0_.sid=?
Hibernate: 
    select
        courses0_.sid as sid2_1_,
        courses0_.cid as cid1_,
        course1_.cid as cid0_0_,
        course1_.cname as cname0_0_ 
    from
        t_student_course courses0_ 
    inner join
        t_course course1_ 
            on courses0_.cid=course1_.cid 
    where
        courses0_.sid=?
[Course [cid=1, cname=语文], Course [cid=2, cname=数学]]

1.3 删除

@Test
    public void deleteOne(){
        Session session = HibernateUtils.openSession();
        session.beginTransaction();
        // -----------------------------------------------------
            session.createQuery("delete from Student where sid=1").executeUpdate();
            
            
        // ------------------------------------------------------
        session.getTransaction().commit();
        session.close();
    
    }
Hibernate: 
    delete 
    from
        t_student 
    where
        sid=1
10:46:16,083  WARN JDBCExceptionReporter:233 - SQL Error: 1451, SQLState: 23000
10:46:16,083 ERROR JDBCExceptionReporter:234 - Cannot delete or update a parent row: a foreign key constraint fails (`hbm_rele`.`t_student_course`, CONSTRAINT `FK3F2869CAEE65BEC0` FOREIGN KEY (`sid`) REFERENCES `t_student` (`sid`))
10:46:16,089  INFO SessionFactoryImpl:927 - closing

这里必须先把中间维护关系的表给更改了才行

@Test
    public void deleteOneWithObj(){
        Session session = HibernateUtils.openSession();
        session.beginTransaction();
        // -----------------------------------------------------
        
            Student student = (Student) session.get(Student.class, 1);
            session.delete(student);
            
        // ------------------------------------------------------
        session.getTransaction().commit();
        session.close();
    
    }
Hibernate: 
    select
        student0_.sid as sid2_0_,
        student0_.name as name2_0_,
        student0_.sex as sex2_0_ 
    from
        t_student student0_ 
    where
        student0_.sid=?
Hibernate: 
    delete 
    from
        t_student_course 
    where
        sid=?
Hibernate: 
    delete 
    from
        t_student 
    where
        sid=?

2.0 一方放弃维护外键(单向多对多)

Student 放弃维护外键

<!--student-->
        <set name="courses" table="t_student_course" inverse="true">
            <key column="sid" not-null="true" ></key>
            <many-to-many  class="Course" column="cid" ></many-to-many>
        </set>

  `cid` int(11) NOT NULL,
  `sid` int(11) NOT NULL,
  PRIMARY KEY (`cid`,`sid`),
  KEY `FK3F2869CAEE65BEC0` (`sid`),
  KEY `FK3F2869CA4E48E42` (`cid`),
  CONSTRAINT `FK3F2869CA4E48E42` FOREIGN KEY (`cid`) REFERENCES `t_course` (`cid
`),
  CONSTRAINT `FK3F2869CAEE65BEC0` FOREIGN KEY (`sid`) REFERENCES `t_student` (`s
id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 |


2.1 调用上面的add函数

Hibernate: 
    insert 
    into
        t_course
        (cname) 
    values
        (?)
Hibernate: 
    insert 
    into
        t_course
        (cname) 
    values
        (?)
Hibernate: 
    insert 
    into
        t_student
        (name, sex) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        t_student
        (name, sex) 
    values
        (?, ?)

这里并不在中间表做关系维护,直白一点,就是说Student已经不关心Course了,所以如果通过把Course 添加到Student的set里,并不能维护关系。

反过来,这里用course 添加student就可以维护关系,hibernate依然会在数据库中通过中间表来维护关系。


    @Test
    public void addInverseFalse() {

        Session session = HibernateUtils.openSession();
        session.beginTransaction();
        // -----------------------------------------------------
        Student s1 = new Student();
        s1.setName("旺旺");
        s1.setSex("男");

        Student s2 = new Student();
        s2.setName("小董");
        s2.setSex("男");

        Course c1 = new Course();
        c1.setCname("语文");
        Course c2 = new Course();
        c2.setCname("数学");

        // 维护关系
        c1.getStudents().add(s1);
        c1.getStudents().add(s2);
        
        c2.getStudents().add(s1);
        c2.getStudents().add(s2);

        session.save(c1);
        session.save(c2);
        session.save(s1);
        session.save(s2);

        // ------------------------------------------------------
        session.getTransaction().commit();
        // session.close();
    }

Hibernate: 
    insert 
    into
        t_course
        (cname) 
    values
        (?)
Hibernate: 
    insert 
    into
        t_course
        (cname) 
    values
        (?)
Hibernate: 
    insert 
    into
        t_student
        (name, sex) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        t_student
        (name, sex) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        t_student_course
        (cid, sid) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        t_student_course
        (cid, sid) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        t_student_course
        (cid, sid) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        t_student_course
        (cid, sid) 
    values
        (?, ?)

所以,同理有:通过Student删除,中间表的关系不会删除,通过Student得到Course并且施加更新,不会生效。

既然你放弃了她,你给的东西,再好她也不要。
勉强得到的,不过是幻梦。(通过Student得到Course,修改并不会写入)

2.2 更新和删除

调用上面的update()

Hibernate: 
    select
        student0_.sid as sid2_0_,
        student0_.name as name2_0_,
        student0_.sex as sex2_0_ 
    from
        t_student student0_ 
    where
        student0_.sid=?
Hibernate: 
    select
        courses0_.sid as sid2_1_,
        courses0_.cid as cid1_,
        course1_.cid as cid0_0_,
        course1_.cname as cname0_0_ 
    from
        t_student_course courses0_ 
    inner join
        t_course course1_ 
            on courses0_.cid=course1_.cid 
    where
        courses0_.sid=?

如果中间表有关系,也就是数据是通过Course维护的,deleteOne()

Hibernate: 
    delete 
    from
        t_student 
    where
        sid=2
11:16:53,179  WARN JDBCExceptionReporter:233 - SQL Error: 1451, SQLState: 23000
11:16:53,180 ERROR JDBCExceptionReporter:234 - Cannot delete or update a parent row: a foreign key constraint fails (`hbm_rele`.`t_student_course`, CONSTRAINT `FK3F2869CAEE65BEC0` FOREIGN KEY (`sid`) REFERENCES `t_student` (`sid`))
11:16:53,188  INFO SessionFactoryImpl:927 - closing

3.0级联加载

3.1Student放弃维护Course,并且级联加载Course

不爱了,为什么还藕断丝连地关心。

<!--student-->
        <set name="courses" table="t_student_course" inverse="true" cascade="all">
            <key column="sid" not-null="true" ></key>
            <many-to-many  class="Course" column="cid" ></many-to-many>
        </set>


    @Test
    public void addInverseTrueCascadeAll() {

        Session session = HibernateUtils.openSession();
        session.beginTransaction();
        // -----------------------------------------------------
        Student s1 = new Student();
        s1.setName("旺旺");
        s1.setSex("男");

        Student s2 = new Student();
        s2.setName("小董");
        s2.setSex("男");

        Course c1 = new Course();
        c1.setCname("语文");
        Course c2 = new Course();
        c2.setCname("数学");

        // 维护关系
        c1.getStudents().add(s1);
        c1.getStudents().add(s2);
        
        c2.getStudents().add(s1);
        c2.getStudents().add(s2);

        session.save(c1);
        session.save(c2);

        // ------------------------------------------------------
        session.getTransaction().commit();
        // session.close();
    }

Hibernate: 
    insert 
    into
        t_course
        (cname) 
    values
        (?)
Hibernate: 
    insert 
    into
        t_course
        (cname) 
    values
        (?)
Hibernate: 
    insert 
    into
        t_student_course
        (cid, sid) 
    values
        (?, ?)
//error

这里会出错,因为student放弃了维护,虽然student级联了course,而course并没有级联student;

可以想象,这里的查询应该可以成功

    
    @Test
    /*
     * student
     *      Inverse:    true
     *      Cascade:    all
     */
    public void findCascadeAll() {
        Session session = HibernateUtils.openSession();
        session.beginTransaction();
        // -----------------------------------------------------
            Student student01 = (Student) session.get(Student.class, 1);
        // ------------------------------------------------------
        session.getTransaction().commit();
        session.close();
        
        System.out.println(student01.getCourses());//没办法找到,这里
    }
    

结果却是:

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: cc.sirius.bean.Student.courses, no session or session was closed
    at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:383)
    at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationExceptionIfNotConnected(AbstractPersistentCollection.java:375)
    at org.hibernate.collection.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:368)
    at org.hibernate.collection.AbstractPersistentCollection.read(AbstractPersistentCollection.java:111)
    at org.hibernate.collection.PersistentSet.toString(PersistentSet.java:332)
    at java.lang.String.valueOf(String.java:2994)
    at java.io.PrintStream.println(PrintStream.java:821)
    at cc.sirius.service.TestDo2.findCascadeAll(TestDo2.java:138)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at ...

这里是懒加载的问题,
set 的lazy默认为true。修改为false


        <set name="courses" table="t_student_course" inverse="true" lazy="false" cascade="all">
            <key column="sid" not-null="true" ></key>
            <many-to-many  class="Course" column="cid" ></many-to-many>
        </set>
Hibernate: 
    select
        student0_.sid as sid2_0_,
        student0_.name as name2_0_,
        student0_.sex as sex2_0_ 
    from
        t_student student0_ 
    where
        student0_.sid=?
Hibernate: 
    select
        courses0_.sid as sid2_1_,
        courses0_.cid as cid1_,
        course1_.cid as cid0_0_,
        course1_.cname as cname0_0_ 
    from
        t_student_course courses0_ 
    inner join
        t_course course1_ 
            on courses0_.cid=course1_.cid 
    where
        courses0_.sid=?
[]

3.2删除

至于删除,如果是student,他放弃了维护外键,但是配置了级联删除

@Test
    public void deleteOneWithObj(){
        Session session = HibernateUtils.openSession();
        session.beginTransaction();
        // -----------------------------------------------------
        
            Student student = (Student) session.get(Student.class, 1);
            session.delete(student);
            
        // ------------------------------------------------------
        session.getTransaction().commit();
        session.close();
    
    }
Hibernate: 
    select
        student0_.sid as sid2_0_,
        student0_.name as name2_0_,
        student0_.sex as sex2_0_ 
    from
        t_student student0_ 
    where
        student0_.sid=?
Hibernate: 
    select
        courses0_.sid as sid2_1_,
        courses0_.cid as cid1_,
        course1_.cid as cid0_0_,
        course1_.cname as cname0_0_ 
    from
        t_student_course courses0_ 
    inner join
        t_course course1_ 
            on courses0_.cid=course1_.cid 
    where
        courses0_.sid=?
Hibernate: 
    delete 
    from
        t_student_course 
    where
        cid=?
Hibernate: 
    delete 
    from
        t_student_course 
    where
        cid=?
Hibernate: 
    delete 
    from
        t_course 
    where
        cid=?
Hibernate: 
    delete 
    from
        t_course 
    where
        cid=?
Hibernate: 
    delete 
    from
        t_student 
    where
        sid=?
  • 删除student02的时候,先查找student02
  • 查找student02的 course
  • 在关联表中把和student选过的课全删了(这里不是只删除student-course那些行)
  • 然后在course中删除student学过的所有课程
  • 最后才是删除student

4.0 Student放弃维护Course,并且双方都级联加载对方

他主动放弃,双方却还牵挂着彼此

为了效果明显,这里懒加载都关掉

4.1 级联插入

public void addInverseTrueCascadeAll() {

        Session session = HibernateUtils.openSession();
        session.beginTransaction();
        // -----------------------------------------------------
        Student s1 = new Student();
        s1.setName("旺旺");
        s1.setSex("男");

        Student s2 = new Student();
        s2.setName("小董");
        s2.setSex("男");

        Course c1 = new Course();
        c1.setCname("语文");
        Course c2 = new Course();
        c2.setCname("数学");

        // 维护关系
        c1.getStudents().add(s1);
        c1.getStudents().add(s2);
        
        c2.getStudents().add(s1);
        c2.getStudents().add(s2);

        session.save(c1);
        session.save(c2);

        // ------------------------------------------------------
        session.getTransaction().commit();
        session.close();
    }

效果:

Hibernate: 
    insert 
    into
        t_course
        (cname) 
    values
        (?)
Hibernate: 
    insert 
    into
        t_student
        (name, sex) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        t_student
        (name, sex) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        t_course
        (cname) 
    values
        (?)
Hibernate: 
    insert 
    into
        t_student_course
        (cid, sid) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        t_student_course
        (cid, sid) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        t_student_course
        (cid, sid) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        t_student_course
        (cid, sid) 
    values
        (?, ?)

4.2 级联更新


public void updateCascadeAll() {
        Session session = HibernateUtils.openSession();
        session.beginTransaction();
        // -----------------------------------------------------

        Course course=(Course) session.get(Course.class,1);
        Iterator<Student> it = course.getStudents().iterator();
        
        while(it.hasNext()){
            it.next().setName("灰太狼");
        }
            
        session.save(course);
        // ------------------------------------------------------
        session.getTransaction().commit();
        session.close();
        
    }

Hibernate: 
    select
        course0_.cid as cid0_0_,
        course0_.cname as cname0_0_ 
    from
        t_course course0_ 
    where
        course0_.cid=?
Hibernate: 
    select
        students0_.cid as cid0_1_,
        students0_.sid as sid1_,
        student1_.sid as sid2_0_,
        student1_.name as name2_0_,
        student1_.sex as sex2_0_ 
    from
        t_student_course students0_ 
    inner join
        t_student student1_ 
            on students0_.sid=student1_.sid 
    where
        students0_.cid=?
Hibernate: 
    select
        courses0_.sid as sid2_1_,
        courses0_.cid as cid1_,
        course1_.cid as cid0_0_,
        course1_.cname as cname0_0_ 
    from
        t_student_course courses0_ 
    inner join
        t_course course1_ 
            on courses0_.cid=course1_.cid 
    where
        courses0_.sid=?
Hibernate: 
    select
        students0_.cid as cid0_1_,
        students0_.sid as sid1_,
        student1_.sid as sid2_0_,
        student1_.name as name2_0_,
        student1_.sex as sex2_0_ 
    from
        t_student_course students0_ 
    inner join
        t_student student1_ 
            on students0_.sid=student1_.sid 
    where
        students0_.cid=?
Hibernate: 
    select
        courses0_.sid as sid2_1_,
        courses0_.cid as cid1_,
        course1_.cid as cid0_0_,
        course1_.cname as cname0_0_ 
    from
        t_student_course courses0_ 
    inner join
        t_course course1_ 
            on courses0_.cid=course1_.cid 
    where
        courses0_.sid=?
Hibernate: 
    update
        t_student 
    set
        name=?,
        sex=? 
    where
        sid=?
Hibernate: 
    update
        t_student 
    set
        name=?,
        sex=? 
    where
        sid=?
image.png

4.3 地狱级别的删除


    @Test
    public void deleteCourse(){
        Session session = HibernateUtils.openSession();
        session.beginTransaction();
        // -----------------------------------------------------
        
            Course course = (Course) session.get(Course.class, 1);
            session.delete(course);
        // ------------------------------------------------------
        session.getTransaction().commit();
        session.close();
    
    }

Hibernate: 
    select
        course0_.cid as cid0_0_,
        course0_.cname as cname0_0_ 
    from
        t_course course0_ 
    where
        course0_.cid=?
Hibernate: 
    select
        students0_.cid as cid0_1_,
        students0_.sid as sid1_,
        student1_.sid as sid2_0_,
        student1_.name as name2_0_,
        student1_.sex as sex2_0_ 
    from
        t_student_course students0_ 
    inner join
        t_student student1_ 
            on students0_.sid=student1_.sid 
    where
        students0_.cid=?
Hibernate: 
    select
        courses0_.sid as sid2_1_,
        courses0_.cid as cid1_,
        course1_.cid as cid0_0_,
        course1_.cname as cname0_0_ 
    from
        t_student_course courses0_ 
    inner join
        t_course course1_ 
            on courses0_.cid=course1_.cid 
    where
        courses0_.sid=?
Hibernate: 
    select
        students0_.cid as cid0_1_,
        students0_.sid as sid1_,
        student1_.sid as sid2_0_,
        student1_.name as name2_0_,
        student1_.sex as sex2_0_ 
    from
        t_student_course students0_ 
    inner join
        t_student student1_ 
            on students0_.sid=student1_.sid 
    where
        students0_.cid=?
Hibernate: 
    select
        courses0_.sid as sid2_1_,
        courses0_.cid as cid1_,
        course1_.cid as cid0_0_,
        course1_.cname as cname0_0_ 
    from
        t_student_course courses0_ 
    inner join
        t_course course1_ 
            on courses0_.cid=course1_.cid 
    where
        courses0_.sid=?
Hibernate: 
    delete 
    from
        t_student_course 
    where
        cid=?
Hibernate: 
    delete 
    from
        t_student_course 
    where
        cid=?
Hibernate: 
    delete 
    from
        t_student 
    where
        sid=?
Hibernate: 
    delete 
    from
        t_course 
    where
        cid=?
Hibernate: 
    delete 
    from
        t_student 
    where
        sid=?
Hibernate: 
    delete 
    from
        t_course 
    where
        cid=?
  • 查找course01
  • 查找course01底下所有student
  • 查找student对应所有course
  • 一直查找,直到course和student之间不再有关联
  • 然后先删除中间表
  • 再删除两个表的数据
  • 结局是两个表的数据基本全废了,等于清表

相关文章

网友评论

      本文标题:hibernate 多对多

      本文链接:https://www.haomeiwen.com/subject/xbgypxtx.html