Hibernate一对多双向关联,以及双向关联在操作many方或one方的区别

结论:

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();
	}
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,这里是使用 C 语言实现判断井字棋布局中是否有选手获胜的代码示例: ```c #include <stdio.h> int main() { char board[3][3] = { {'X', 'O', 'X'}, {'O', 'X', 'O'}, {'X', 'O', 'X'} }; int i, j; int isWin = 0; // 是否有选手获胜的标记 // 判断是否有选手获胜 for (i = 0; i < 3; i++) { // 判断横线 if (board[i][0] == board[i][1] && board[i][1] == board[i][2]) { printf("%c获胜!\n", board[i][0]); isWin = 1; break; } // 判断竖线 if (board[0][i] == board[1][i] && board[1][i] == board[2][i]) { printf("%c获胜!\n", board[0][i]); isWin = 1; break; } } // 判断斜线 if (!isWin && board[1][1] != ' ' && ((board[0][0] == board[1][1] && board[1][1] == board[2][2]) || (board[0][2] == board[1][1] && board[1][1] == board[2][0]))) { printf("%c获胜!\n", board[1][1]); isWin = 1; } // 判断平局 if (!isWin) { printf("平局!\n"); } return 0; } ``` 在这个代码中,我们首先使用一个 3 × 3 的二维字符数组 board 来保存井字棋布局。接着,我们使用三个 for 循环来遍历这个数组,并判断是否有选手获胜。在内部的循环中,我们首先判断是否有横线或者竖线,如果有,则输出获胜者的字符,并将 isWin 的值标记为 1;否则,我们再判断是否有斜线,如果有,则同样输出获胜者的字符,并将 isWin 的值标记为 1;最后,如果 isWin 的值仍然为 0,则说明没有选手获胜,输出平局的结果。 希望这个代码能够帮助到你,如果你有任何问题,可以随时问我。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值