Hibernate一对多双向关联,以及双向关联在操作many方或one方的区别
2013-09-27 17:26
357 查看
结论:
1、一对多双向关联的时候,大部分时候,在many方进行关联关系的操作性能要优于在one方操作。因为在many操作,many直接设置了many方的外键了,而不需要用update语句来维护外键。
2、many-to-one标签里没有inverse属性,原因是操作many方的时候会直接维护many方和one方的关联关系
3、如果难以确定关联关系是哪一方维护的时候,可以改变inverse属性(true),来进行测试。如果one方设置了inverse=true
那么,如果是one方进行维护关联关系,此时向数据库级联插入一条数据,many方的外键必定为null。如果many方的外键有值,则证明是one方在维护关联关系。
Student
Student.hbm.xml
Class
Class.hbm.xml
oneToMany双向关联测试类:
1、一对多双向关联的时候,大部分时候,在many方进行关联关系的操作性能要优于在one方操作。因为在many操作,many直接设置了many方的外键了,而不需要用update语句来维护外键。
2、many-to-one标签里没有inverse属性,原因是操作many方的时候会直接维护many方和one方的关联关系
3、如果难以确定关联关系是哪一方维护的时候,可以改变inverse属性(true),来进行测试。如果one方设置了inverse=true
那么,如果是one方进行维护关联关系,此时向数据库级联插入一条数据,many方的外键必定为null。如果many方的外键有值,则证明是one方在维护关联关系。
Student
public class Student implements Serializable{ private Long sid; private String sname; private String description; private Class clzz; public Long getSid() { return sid; } public void setSid(Long sid) { this.sid = sid; } public String getSname() { return sname; } public void setSname(String sname) { this.sname = sname; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public Class getClzz() { return clzz; } public void setClzz(Class clzz) { this.clzz = clzz; } }
Student.hbm.xml
<!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.xxc.one2many_bothway.Student"> <id name="sid" type="long" length="5"> <column name="sid"/> <generator class="identity"/> </id> <property name="sname" type="string" length="20"/> <property name="description" type="string" length="100"/> <!-- 多对一关联关系: 建立student到class的关联,这里定义column并不会和 Class.hbm.xml中的key column="cid"冲突 因为hibernate操作类的时候,操作哪个类,就参照哪个类的映射文件 加了这个参数,只是代表了student类可以访问到class类了,数据库的表结构不会发生任何变化 --> <many-to-one name="clzz" column="cid" cascade="all"></many-to-one> </class> </hibernate-mapping>
Class
public class Class implements Serializable{ private Long cid; private String cname; private String description; private Set<Student> students; public Long getCid() { return cid; } public void setCid(Long cid) { this.cid = cid; } public String getCname() { return cname; } public void setCname(String cname) { this.cname = cname; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public Set<Student> getStudents() { return students; } public void setStudents(Set<Student> students) { this.students = students; } }
Class.hbm.xml
<!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.xxc.one2many_bothway.Class"> <id name="cid" type="long"> <column name="cid" length="5"/> <generator class="identity"/> </id> <property name="cname" type="string" length="20"/> <property name="description" type="string" length="100"/> <!-- set元素对应类型的set集合,通过set元素使class表和student表建立关系 *key是通过外键的形式让两张表建立关联 *one-to-many是通过类的形式让两个类建立关联 Ⅰ.cascade:级联保存,在操作class的时候同时操作student,只保存student的一般属性,而不会去操作student表的外键 * 当保存班级对象的时候,学生对象会发生如下操作 1.如果学生对象在数据库中没有对应的值(看id),这个时候会执行save操作 2.如果学生对象在数据库中有对应的值(看id),这个时候会执行update操作 Ⅱ.inverse:表示当前映射文件所映射的类,是否维护和set集合里的的类之间的关联关系,如果为false则会去操作student表中外键的值 缺省为false。 --> <set name="students" inverse="false" cascade="all"> <!-- key用于描述外键 --> <key column="cid"></key><!-- cid表示student表中的外键 --> <one-to-many class="com.xxc.one2many_bothway.Student"/><!-- 跟哪个类建立关系 --> </set> </class> </hibernate-mapping>
oneToMany双向关联测试类:
package com.xxc.one2many_bothway; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import org.hibernate.Query; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import org.junit.Test; /** * 1、新建一个班级的时候同时新建一个学生 * 2、已经存在一个班级,新建一个学生,建立学生与班级之间的关系 * 3、已经存在一个学生,新建一个班级,把学生加入到该班级 * 4、把一个学生从一个班级转移到另一个班级 * 5、解除一个班级和一个学生之间的关系 * 6、解除一个班级和一些学生之间的关系 * 7、解除该班级和所有的学生之间的关系 * 8、已经存在一个班级,已经存在一个学生,建立该班级与该学生之间的关系 * 9、已经存在一个班级,已经存在多个学生,建立多个学生与班级之间的关系 * 10、删除学生 * 11、删除班级 * 删除班级的时候同时删除学生 * 在删除班级之前,解除班级和学生之间的关系 */ public class One2ManyTest { private static SessionFactory sessionFactory; static{ Configuration con = new Configuration().configure(); sessionFactory = con.buildSessionFactory(); } /** * 1(1).新建一个班级的时候同时新建一个学生(在班级对象里设置学生,保存班级对象) * * session.save(clzz);的时候会执行如下两句sql---->插入两条数据,这两条数据之间还没有建立关系 * Hibernate: insert into Class (cname, description) values (?, ?) * Hibernate: insert into Student (sname, description, cid) values (?, ?, ?) * * transaction.commit();的时候会执行下面的sql,也就是维护student表的外键 * Hibernate: update Student set cid=? where sid=? */ @Test public void testSaveStudent_Cascade_SaveClass(){ Session session = sessionFactory.openSession(); Transaction transaction = session.beginTransaction(); Student stu = new Student(); stu.setSname("xxc1"); stu.setDescription("1"); Set<Student> stus = new HashSet<Student>(); stus.add(stu); Class clzz = new Class(); clzz.setCname("浙江大学一院"); clzz.setDescription("1"); clzz.setStudents(stus); //保存班级,级联保存学生 session.save(clzz); transaction.commit(); session.close(); } /** * 显然,在一对多双向关联进行级联保存数据的时候,在many的一方进行级联保存的效率要高于在one那方进行级联保存操作 * 因为,many方在进行保存数据的时候会自动维护many方和one方的关联关系 * * 1(2).新建一个班级的时候同时新建一个学生(在学生对象里设置班级对象,保存学生对象) * * 在学生对象里级联操作班级对象,进行了如下两句sql插入语句,发现并没有出现 * 像在班级里级联操作学生对象的update语句 * Hibernate: insert into Class (cname, description) values (?, ?) * Hibernate: insert into Student (sname, description, cid) values (?, ?, ?) */ @Test public void testSaveStudent_Cascade_ClassSave(){ Session session = sessionFactory.openSession(); Transaction transaction = session.beginTransaction(); Class clzz = new Class(); clzz.setCname("浙江大学一院"); clzz.setDescription("1"); Student stu = new Student(); stu.setSname("xxc1"); stu.setDescription("1"); stu.setClzz(clzz); //保存学生,级联保存班级 session.save(stu); transaction.commit(); session.close(); } /** * 2(1).已经存在一个班级,新建一个学生,建立学生与班级之间的关系(在班级对象里设置学生,保存班级对象) * * session.get(Class.class, 18L)会执行以下sql * Hibernate: select class0_.cid as cid0_0_, class0_.cname as cname0_0_, class0_.description as descript3_0_0_ from Class class0_ where class0_.cid=? * * clzz.getStudents()会执行以下sql * Hibernate: select students0_.cid as cid0_1_, students0_.sid as sid1_, students0_.sid as sid1_0_, students0_.sname as sname1_0_, students0_.description as descript3_1_0_, students0_.cid as cid1_0_ from Student students0_ where students0_.cid=? * * clzz.getStudents().add(stu) * transaction.commit(); 在事务提交的时候会进行以下sql * Hibernate: insert into Student (sname, description, cid) values (?, ?, ?) 这时student和class两条数据之间是没有任何关系的 * Hibernate: update Student set cid=? where sid=? 因为这个例子中是由class对象来维护关联关系的,所以要通过查找刚才插入的student数据的sid来修改它的外键cid */ @Test public void testSaveStudent_Cascade_ClassSave_forNewClassAndNewStudent(){ Session session = sessionFactory.openSession(); Transaction transaction = session.beginTransaction(); Class clzz = (Class) session.get(Class.class, 18L); Student stu = new Student(); stu.setSname("xxc2"); stu.setDescription("2"); //由于clzz是持久化状态对象,所以不需要进行update操作 clzz.getStudents().add(stu); transaction.commit(); session.close(); } /** * 2(1).已经存在一个班级,新建一个学生,建立学生与班级之间的关系(在学生对象里设置班级对象,保存学生对象,由学生来维护关系) * * session.get(Class.class, 18L);会执行以下sql * Hibernate: select class0_.cid as cid0_0_, class0_.cname as cname0_0_, class0_.description as descript3_0_0_ from Class class0_ where class0_.cid=? * * session.save(stu);会执行以下sql 由一对多,多的一端直接负责维护关联关系,在插入student的时候就直接把cid外键给设值了 * Hibernate: insert into Student (sname, description, cid) values (?, ?, ?) */ @Test public void testSaveClass_Cascade_StudentSave_forNewClassAndNewStudent(){ Session session = sessionFactory.openSession(); Transaction transaction = session.beginTransaction(); Class clzz = (Class) session.get(Class.class, 18L); Student stu = new Student(); stu.setSname("xxc2"); stu.setDescription("2"); stu.setClzz(clzz);//由student对象来维护关系 session.save(stu); transaction.commit(); session.close(); } /** * 测试:由class来保存关系,但是save的是student对象,最终是靠哪个类来维护关联关系 * 可以通过将class.hbm.xml映射文件中的inverse="true"来验证 * 如果插入的student数据的外键为null,证明是由class类来维护关系的,如果是插入的外键不为null,那么表示是student类来维护关系的 * * 2(2).已经存在一个班级,新建一个学生,建立学生与班级之间的关系(在班级对象里设置学生对象,保存学生对象,由班级对象维护关系) 不推荐!!! * 正确做法是让同一端负责维护关系和保存. * * session.get(Class.class, 18L);执行以下sql * Hibernate: select class0_.cid as cid0_0_, class0_.cname as cname0_0_, class0_.description as descript3_0_0_ from Class class0_ where class0_.cid=? * clzz.getStudents()执行以下sql * Hibernate: select students0_.cid as cid0_1_, students0_.sid as sid1_, students0_.sid as sid1_0_, students0_.sname as sname1_0_, students0_.description as descript3_1_0_, students0_.cid as cid1_0_ from Student students0_ where students0_.cid=? * session.save(stu);执行以下sql * Hibernate: insert into Student (sname, description, cid) values (?, ?, ?) * 结果是数据库中student数据的外键为null * * 根据结果看可以得出:save方法并不用于维护关联关系,它只是起保存数据作用而已,所以维护关联关系是clzz.getStudents().add(stu)起的作用, * 由于是class类来维护关系,那么就要参照Class.hbm.xml中的inverse配置 * * 如果Class.hbm.xml映射文件中inverse="false",会执行以下sql,从而也看出了在一对多双向关联的时候,由one方来维护关联关系效率较低 * Hibernate: update Student set cid=? where sid=? */ @Test public void testSaveClass_Cascade_StudentSave_forNewClassAndNewStudent_ClassInverseTrue(){ Session session = sessionFactory.openSession(); Transaction transaction = session.beginTransaction(); Class clzz = (Class) session.get(Class.class, 18L); Student stu = new Student(); stu.setSname("xxc2"); stu.setDescription("2"); clzz.getStudents().add(stu); session.save(stu); transaction.commit(); session.close(); } /** * 3(1)、已经存在一个学生,新建一个班级,把学生加入到该班级(在班级对象里设置学生,保存班级对象) * * session.get(Student.class, 40L);会执行以下sql * Hibernate: select student0_.sid as sid1_0_, student0_.sname as sname1_0_, student0_.description as descript3_1_0_, student0_.cid as cid1_0_ from Student student0_ where student0_.sid=? * session.save(clzz);会执行以下sql * Hibernate: insert into Class (cname, description) values (?, ?) * commit会执行以下sql * Hibernate: update Student set cid=? where sid=? */ @Test public void test3_1(){ Session session = sessionFactory.openSession(); Transaction transaction = session.beginTransaction(); Student stu = (Student) session.get(Student.class, 40L); Class clzz = new Class(); clzz.setCname("浙大三院"); clzz.setDescription("3"); Set<Student> stus = new HashSet<Student>(); stus.add(stu); clzz.setStudents(stus); session.save(clzz); transaction.commit(); session.close(); } /** * 3(2)、已经存在一个学生,新建一个班级,把学生加入到该班级(在学生对象里设置班级对象,保存学生对象) * * session.get(Student.class, 40L); * Hibernate: select student0_.sid as sid1_0_, student0_.sname as sname1_0_, student0_.description as descript3_1_0_, student0_.cid as cid1_0_ from Student student0_ where student0_.sid=? * 由于是new了一个Class对象,所以要进行插入sql * Hibernate: insert into Class (cname, description) values (?, ?) * 因为前面连student数据关联的class数据都还没创建,不可能直接设置student的cid,所以这里还要进行一句update * Hibernate: update Student set sname=?, description=?, cid=? where sid=? * */ @Test public void test3_2(){ Session session = sessionFactory.openSession(); Transaction transaction = session.beginTransaction(); Student stu = (Student) session.get(Student.class, 40L); Class clzz = new Class(); clzz.setCname("浙大三院"); clzz.setDescription("3"); stu.setClzz(clzz); session.save(stu); transaction.commit(); session.close(); } /** * 4(1)、把一个学生从一个班级转移到另一个班级(在班级对象里设置学生,保存班级对象) * 由于学生和班级都是从数据库里查询出来的,所以student并不是多了一条数据,而是将查询出来的数据的cid改变 * * session.get(Student.class, 40L);会执行以下sql * Hibernate: select student0_.sid as sid1_0_, student0_.sname as sname1_0_, student0_.description as descript3_1_0_, student0_.cid as cid1_0_ from Student student0_ where student0_.sid=? * session.get(Class.class, 18L);会执行以下sql * Hibernate: select class0_.cid as cid0_0_, class0_.cname as cname0_0_, class0_.description as descript3_0_0_ from Class class0_ where class0_.cid=? * clzz.getStudents()会执行以下sql * Hibernate: select students0_.cid as cid0_1_, students0_.sid as sid1_, students0_.sid as sid1_0_, students0_.sname as sname1_0_, students0_.description as descript3_1_0_, students0_.cid as cid1_0_ from Student students0_ where students0_.cid=? * clzz.getStudents().add(stu); commit的时候执行以下sql * Hibernate: update Student set cid=? where sid=? * */ @Test public void test4_1(){ Session session = sessionFactory.openSession(); Transaction transaction = session.beginTransaction(); Student stu = (Student) session.get(Student.class, 40L); Class clzz = (Class) session.get(Class.class, 18L); //clzz是持久化状态对象,所以这里不需要update clzz.getStudents().add(stu); transaction.commit(); session.close(); } /** * 4(2)、把一个学生从一个班级转移到另一个班级(在学生对象里设置班级对象,保存学生对象) * * session.get(Student.class, 40L);会执行以下sql * Hibernate: select student0_.sid as sid1_0_, student0_.sname as sname1_0_, student0_.description as descript3_1_0_, student0_.cid as cid1_0_ from Student student0_ where student0_.sid=? * session.get(Class.class, 18L);会执行以下sql * Hibernate: select class0_.cid as cid0_0_, class0_.cname as cname0_0_, class0_.description as descript3_0_0_ from Class class0_ where class0_.cid=? * stu.setClzz(clzz); commit的时候执行以下sql * Hibernate: update Student set sname=?, description=?, cid=? where sid=? * */ @Test public void test4_2(){ Session session = sessionFactory.openSession(); Transaction transaction = session.beginTransaction(); Student stu = (Student) session.get(Student.class, 40L); Class clzz = (Class) session.get(Class.class, 18L); stu.setClzz(clzz); transaction.commit(); session.close(); } /** * 5(1)、解除一个班级和一个学生之间的关系(在班级对象里设置学生,保存班级对象) * * session.get(Class.class, 18L);会执行以下sql * Hibernate: select class0_.cid as cid0_0_, class0_.cname as cname0_0_, class0_.description as descript3_0_0_ from Class class0_ where class0_.cid=? * session.get(Student.class, 40L);会执行以下sql * Hibernate: select student0_.sid as sid1_0_, student0_.sname as sname1_0_, student0_.description as descript3_1_0_, student0_.cid as cid1_0_ from Student student0_ where student0_.sid=? * clzz.getStudents()会执行以下sql * Hibernate: select students0_.cid as cid0_1_, students0_.sid as sid1_, students0_.sid as sid1_0_, students0_.sname as sname1_0_, students0_.description as descript3_1_0_, students0_.cid as cid1_0_ from Student students0_ where students0_.cid=? * clzz.getStudents().remove(stu); commit的时候执行以下sql * Hibernate: update Student set cid=null where cid=? */ @Test public void test5_1(){ Session session = sessionFactory.openSession(); Transaction transaction = session.beginTransaction(); Class clzz = (Class) session.get(Class.class, 18L); Student stu = (Student) session.get(Student.class, 40L); //从class对象中的student集合删除查询出来的student对象 clzz.getStudents().remove(stu); transaction.commit(); session.close(); } /** * 5(2)、解除一个班级和一个学生之间的关系(在学生对象里设置班级对象,保存学生对象) * * session.get(Student.class, 40L);会执行以下sql * Hibernate: select student0_.sid as sid1_0_, student0_.sname as sname1_0_, student0_.description as descript3_1_0_, student0_.cid as cid1_0_ from Student student0_ where student0_.sid=? * stu.setClzz(null); commit的时候会执行以下sql * Hibernate: update Student set sname=?, description=?, cid=? where sid=? */ @Test public void test5_2(){ Session session = sessionFactory.openSession(); Transaction transaction = session.beginTransaction(); Student stu = (Student) session.get(Student.class, 40L); stu.setClzz(null); transaction.commit(); session.close(); } /** * 可以看出:由one方解除关联关系,效率较低 * 6(1).解除一个班级和一些学生之间的关系(由班级类来解除关系) * session.get(Class.class, 18L);会执行以下sql * Hibernate: select class0_.cid as cid0_0_, class0_.cname as cname0_0_, class0_.description as descript3_0_0_ from Class class0_ where class0_.cid=? * session.get(Student.class,40L);会执行以下sql * Hibernate: select student0_.sid as sid1_0_, student0_.sname as sname1_0_, student0_.description as descript3_1_0_, student0_.cid as cid1_0_ from Student student0_ where student0_.sid=? * session.get(Student.class,41L);会执行以下sql * Hibernate: select student0_.sid as sid1_0_, student0_.sname as sname1_0_, student0_.description as descript3_1_0_, student0_.cid as cid1_0_ from Student student0_ where student0_.sid=? * clzz.getStudents();会执行以下sql * Hibernate: select students0_.cid as cid0_1_, students0_.sid as sid1_, students0_.sid as sid1_0_, students0_.sname as sname1_0_, students0_.description as descript3_1_0_, students0_.cid as cid1_0_ from Student students0_ where students0_.cid=? * clzz.getStudents().remove(stu1); * clzz.getStudents().remove(stu2); * 在commit的时候执行以下sql * Hibernate: update Student set cid=null where cid=? and sid=? * Hibernate: update Student set cid=null where cid=? and sid=? */ @Test public void testRelieveRelationClassStudent_Class(){ Session session = sessionFactory.openSession(); Transaction transaction = session.beginTransaction(); Class clzz = (Class) session.get(Class.class, 18L); Student stu1 = (Student) session.get(Student.class,40L); Student stu2 = (Student) session.get(Student.class,41L); //由class类来解除关联关系 clzz.getStudents().remove(stu1); clzz.getStudents().remove(stu2); transaction.commit(); session.close(); } /** * 6(2).解除一个班级和一些学生之间的关系(由学生类来解除关系) * session.get(Class.class, 18L);会执行以下sql * Hibernate: select class0_.cid as cid0_0_, class0_.cname as cname0_0_, class0_.description as descript3_0_0_ from Class class0_ where class0_.cid=? * session.get(Student.class,40L);会执行以下sql * Hibernate: select student0_.sid as sid1_0_, student0_.sname as sname1_0_, student0_.description as descript3_1_0_, student0_.cid as cid1_0_ from Student student0_ where student0_.sid=? * session.get(Student.class,41L);会执行以下sql * Hibernate: select student0_.sid as sid1_0_, student0_.sname as sname1_0_, student0_.description as descript3_1_0_, student0_.cid as cid1_0_ from Student student0_ where student0_.sid=? * stu1.setClzz(null); commit执行 * Hibernate: update Student set sname=?, description=?, cid=? where sid=? * stu2.setClzz(null); commit执行 * Hibernate: update Student set sname=?, description=?, cid=? where sid=? */ @Test public void testRelieveRelationClassStudent_Student(){ Session session = sessionFactory.openSession(); Transaction transaction = session.beginTransaction(); Class clzz = (Class) session.get(Class.class, 18L); Student stu1 = (Student) session.get(Student.class,40L); Student stu2 = (Student) session.get(Student.class,41L); //由student类来解除关系 stu1.setClzz(null); stu2.setClzz(null); transaction.commit(); session.close(); } /** * 7(1).解除该班级和所有的学生之间的关系(在班级对象里设置学生,保存班级对象) * * session.get(Class.class, 18L);会执行以下sql * Hibernate: select class0_.cid as cid0_0_, class0_.cname as cname0_0_, class0_.description as descript3_0_0_ from Class class0_ where class0_.cid=? * clzz.getStudents()会执行以下sql * Hibernate: select students0_.cid as cid0_1_, students0_.sid as sid1_, students0_.sid as sid1_0_, students0_.sname as sname1_0_, students0_.description as descript3_1_0_, students0_.cid as cid1_0_ from Student students0_ where students0_.cid=? * clzz.getStudents().clear(); 在commit的时候会执行以下sql * Hibernate: update Student set cid=null where cid=? */ @Test public void test7_1(){ Session session = sessionFactory.openSession(); Transaction transaction = session.beginTransaction(); Class clzz = (Class) session.get(Class.class, 18L); clzz.getStudents().clear(); transaction.commit(); session.close(); } /** * 7(2).解除该班级和所有的学生之间的关系(在学生对象里设置班级对象,保存学生对象) * 这种情况较为特殊,还是由class类来解除和所有学生之间的关系的效率高 * * session.get(Class.class, 18L);会执行以下sql * Hibernate: select class0_.cid as cid0_0_, class0_.cname as cname0_0_, class0_.description as descript3_0_0_ from Class class0_ where class0_.cid=? * clzz.getStudents();会执行以下sql * Hibernate: select students0_.cid as cid0_1_, students0_.sid as sid1_, students0_.sid as sid1_0_, students0_.sname as sname1_0_, students0_.description as descript3_1_0_, students0_.cid as cid1_0_ from Student students0_ where students0_.cid=? * stu.setClzz(null); 在commit的时候会执行以下sql * Hibernate: update Student set sname=?, description=?, cid=? where sid=? * Hibernate: update Student set sname=?, description=?, cid=? where sid=? * Hibernate: update Student set sname=?, description=?, cid=? where sid=? */ @Test public void test7_2(){ Session session = sessionFactory.openSession(); Transaction transaction = session.beginTransaction(); Class clzz = (Class) session.get(Class.class, 18L); Set<Student> stus = clzz.getStudents(); for(Student stu : stus){ stu.setClzz(null); } transaction.commit(); session.close(); } /** * 8(1).已经存在一个班级,已经存在一个学生,建立该班级与该学生之间的关系(在班级对象里设置学生,保存班级对象) * * session.get(Student.class, 40L);会执行以下sql * Hibernate: select student0_.sid as sid1_0_, student0_.sname as sname1_0_, student0_.description as descript3_1_0_, student0_.cid as cid1_0_ from Student student0_ where student0_.sid=? * session.save(clzz); commit会执行以下sql * Hibernate: insert into Class (cname, description) values (?, ?) * stus.add(stu); clzz.setStudents(stus);由 class来维护关系 commit执行以下sql * Hibernate: update Student set cid=? where sid=? */ @Test public void test8_1(){ Session session = sessionFactory.openSession(); Transaction transaction = session.beginTransaction(); Student stu = (Student) session.get(Student.class, 40L); Class clzz = new Class(); clzz.setCname("浙大8院"); clzz.setDescription("8"); HashSet<Student> stus = new HashSet<Student>(); stus.add(stu); clzz.setStudents(stus); session.save(clzz); transaction.commit(); session.close(); } /** * 8(2).已经存在一个班级,已经存在一个学生,建立该班级与该学生之间的关系(在学生对象里设置班级对象,保存学生对象) * 由于class对象是新创建出来的,所以先查询出来的对象必须等到class插入数据库后才能 设置student的cid的值,所以这种情况下 8(1)和8(2)效率一样 * * session.get(Student.class, 40L);会执行以下sql * Hibernate: select student0_.sid as sid1_0_, student0_.sname as sname1_0_, student0_.description as descript3_1_0_, student0_.cid as cid1_0_ from Student student0_ where student0_.sid=? * 保存新创建的clzz对象 * Hibernate: insert into Class (cname, description) values (?, ?) * 建立新创建的clzz对象和查询出来的student对象间的关系 * Hibernate: update Student set sname=?, description=?, cid=? where sid=? */ @Test public void test8_2(){ Session session = sessionFactory.openSession(); Transaction transaction = session.beginTransaction(); Student stu = (Student) session.get(Student.class, 40L); Class clzz = new Class(); clzz.setCname("浙大8院"); clzz.setDescription("8"); stu.setClzz(clzz); transaction.commit(); session.close(); } /** * 9(1).已经存在一个班级,已经存在多个学生,建立多个学生与班级之间的关系(在班级对象里设置学生,保存班级对象) * * session.get(Class.class, 19L);会执行以下sql * Hibernate: select class0_.cid as cid0_0_, class0_.cname as cname0_0_, class0_.description as descript3_0_0_ from Class class0_ where class0_.cid=? * query.list();会执行以下sql * Hibernate: select student0_.sid as sid1_, student0_.sname as sname1_, student0_.description as descript3_1_, student0_.cid as cid1_ from Student student0_ where student0_.sid in (40 , 41 , 42) * clzz.getStudents()会执行以下sql * Hibernate: select students0_.cid as cid0_1_, students0_.sid as sid1_, students0_.sid as sid1_0_, students0_.sname as sname1_0_, students0_.description as descript3_1_0_, students0_.cid as cid1_0_ from Student students0_ where students0_.cid=? * clzz.getStudents().addAll(list_stu); commit的时候会执行以下sql * Hibernate: update Student set cid=? where sid=? * Hibernate: update Student set cid=? where sid=? * Hibernate: update Student set cid=? where sid=? */ @Test public void test9_1(){ Session session = sessionFactory.openSession(); Transaction transaction = session.beginTransaction(); Class clzz = (Class) session.get(Class.class, 19L); Query query = session.createQuery("from Student s where s.id in(40,41,42)"); List<Student> list_stu = query.list(); clzz.getStudents().addAll(list_stu); transaction.commit(); session.close(); } /** * 9(2).已经存在一个班级,已经存在多个学生,建立多个学生与班级之间的关系(在学生对象里设置班级对象,保存学生对象) * 这个要比9(1)效率要高,唯一的区别就是 9(1)中多查询了次班级所拥有的student集合 * * session.get(Class.class, 19L);会执行以下sql * Hibernate: select class0_.cid as cid0_0_, class0_.cname as cname0_0_, class0_.description as descript3_0_0_ from Class class0_ where class0_.cid=? * query.list();会执行以下sql * Hibernate: select student0_.sid as sid1_, student0_.sname as sname1_, student0_.description as descript3_1_, student0_.cid as cid1_ from Student student0_ where student0_.sid in (40 , 41 , 42) * stu.setClzz(clzz); commit的时候会执行以下sql * Hibernate: update Student set sname=?, description=?, cid=? where sid=? * Hibernate: update Student set sname=?, description=?, cid=? where sid=? * Hibernate: update Student set sname=?, description=?, cid=? where sid=? */ @Test public void test9_2(){ Session session = sessionFactory.openSession(); Transaction transaction = session.beginTransaction(); Class clzz = (Class) session.get(Class.class, 19L); Query query = session.createQuery("from Student s where s.id in(40,41,42)"); List<Student> list_stu = query.list(); for(Student stu : list_stu){ stu.setClzz(clzz); } transaction.commit(); session.close(); } /** * 10(1).删除学生(在班级对象里设置学生,保存班级对象) * 错误原因:因为student是由class对象的关联关系中获取的,所以要删除student,必须先解除class到student之间的关联 * org.hibernate.ObjectDeletedException: * deleted object would be re-saved by cascade (remove deleted object from associations): [com.xxc.one2many_bothway.Student#41] * session.get(Class.class, 19L);会执行以下sql * Hibernate: select class0_.cid as cid0_0_, class0_.cname as cname0_0_, class0_.description as descript3_0_0_ from Class class0_ where class0_.cid=? * clzz.getStudents();会执行以下sql * Hibernate: select students0_.cid as cid0_1_, students0_.sid as sid1_, students0_.sid as sid1_0_, students0_.sname as sname1_0_, students0_.description as descript3_1_0_, students0_.cid as cid1_0_ from Student students0_ where students0_.cid=? * clzz.setStudents(null);会执行以下sql * Hibernate: update Student set cid=null where cid=? * session.delete(stu);会执行以下sql * Hibernate: delete from Student where sid=? * Hibernate: delete from Student where sid=? * Hibernate: delete from Student where sid=? */ @Test public void test10_1(){ Session session = sessionFactory.openSession(); Transaction transaction = session.beginTransaction(); Class clzz = (Class) session.get(Class.class, 19L); Set<Student> stus = clzz.getStudents(); //正确做法是 clzz.setStudents(null); for(Student stu : stus){ /**********加了这两句也还是报错,证明并不是因为student的外键存在才导致这个错误**********/ /*stu.setClzz(null); transaction.commit();*/ /************************/ session.delete(stu); } transaction.commit(); session.close(); } /** * 10(2).删除学生(在学生对象里设置班级对象,保存学生对象) * * session.get(Class.class, 19L);会执行以下sql * Hibernate: select class0_.cid as cid0_0_, class0_.cname as cname0_0_, class0_.description as descript3_0_0_ from Class class0_ where class0_.cid=? * query_stu.list();会执行以下sql * Hibernate: select student0_.sid as sid1_, student0_.sname as sname1_, student0_.description as descript3_1_, student0_.cid as cid1_ from Student student0_ where student0_.sid in (1 , 2 , 3) * session.delete(stu);会执行以下sql * Hibernate: delete from Student where sid=? * Hibernate: delete from Student where sid=? * Hibernate: delete from Student where sid=? */ @Test public void test10_2(){ Session session = sessionFactory.openSession(); Transaction transaction = session.beginTransaction(); Class clzz = (Class) session.get(Class.class, 19L); Query query_stu = session.createQuery("from Student s where s.id in (1,2,3)"); List<Student> list_stu = query_stu.list(); for(Student stu : list_stu){ session.delete(stu); } transaction.commit(); session.close(); } /** * 11(1).删除班级 删除班级的时候同时删除学生 在删除班级之前,解除班级和学生之间的关系(在班级对象里设置学生,保存班级对象) * session.get(Class.class, 23L);会执行以下sql * Hibernate: select class0_.cid as cid0_0_, class0_.cname as cname0_0_, class0_.description as descript3_0_0_ from Class class0_ where class0_.cid=? * session.delete(clzz);会执行以下sql * Hibernate: select students0_.cid as cid0_1_, students0_.sid as sid1_, students0_.sid as sid1_0_, students0_.sname as sname1_0_, students0_.description as descript3_1_0_, students0_.cid as cid1_0_ from Student students0_ where students0_.cid=? * Hibernate: update Student set cid=null where cid=? * Hibernate: delete from Student where sid=? * Hibernate: delete from Student where sid=? * Hibernate: delete from Student where sid=? * Hibernate: delete from Class where cid=? */ @Test public void test11_1(){ Session session = sessionFactory.openSession(); Transaction transaction = session.beginTransaction(); Class clzz = (Class) session.get(Class.class, 23L); session.delete(clzz); transaction.commit(); session.close(); } /** * 11(2).删除班级 删除班级的时候同时删除学生 在删除班级之前,解除班级和学生之间的关系(在学生对象里设置班级对象,保存学生对象) * * session.get(Class.class, 22L);会执行以下sql * Hibernate: select class0_.cid as cid0_0_, class0_.cname as cname0_0_, class0_.description as descript3_0_0_ from Class class0_ where class0_.cid=? * clzz.getStudents();会执行以下sql * Hibernate: select students0_.cid as cid0_1_, students0_.sid as sid1_, students0_.sid as sid1_0_, students0_.sname as sname1_0_, students0_.description as descript3_1_0_, students0_.cid as cid1_0_ from Student students0_ where students0_.cid=? * session.delete(stu);会执行以下sql * Hibernate: update Student set cid=null where cid=? * Hibernate: delete from Student where sid=? * Hibernate: delete from Student where sid=? * Hibernate: delete from Student where sid=? * Hibernate: delete from Class where cid=? */ @Test public void test11_2(){ Session session = sessionFactory.openSession(); Transaction transaction = session.beginTransaction(); Class clzz = (Class) session.get(Class.class, 22L); Set<Student> stus = clzz.getStudents(); for(Student stu : stus){ session.delete(stu); } transaction.commit(); session.close(); } }
相关文章推荐
- Hibernate一对一双向关联映射以及相互引用toString()方法的错误原因
- Hibernate中的双向多对一关联以及 inverse属性、cascade属性的用法
- hibernate的多对一,一对多单向关联,双向关联区别与联系
- Hibernate关系映射 一对一双向外键关联@OneToOne Annotation方式 双向关联和单向关联的区别
- hibernate单向关联与双向关联的区别(原)
- hibernate单向关联和双向关联的区别
- hibernate学习(二)list与iterator区别,一对多双向关联配置
- Hibernate关联映射之一对多,多对一以及双向一对多
- Hibernate关系映射(二)一对一双向外键关联@OneToOne Annotation方式
- Hibernate关联映射 --- 一对多实例分析(双向关联)
- hibernate中merge的使用以及与update的区别
- Hibernate的学习之路二十(一对多的双向关联保存数据)
- Hibernate的关联映射---6.1.6: 双向n-n关联
- Android中Calendar与Date的区别以及消除时区对日期操作影响的方法
- 【Hibernate步步为营】--双向关联一对一映射详解(二)
- Hibernate的双向1-N关联(五)
- C++ 涉及到STL 中 map与multimap的基本操作 以及相应的区别 20180325day13
- mybatis与hibernate本质的区别以及应用的场景
- Hibernate在关于一对多,多对一双向关联映射
- Hibernate 关联映射之---- 一对多双向映射