您的位置:首页 > 其它

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

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();
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: