记得上次学习Hibernate已经很多很多天了,工作中又很少用的到,所以复习一下,首先从hibernate的映射开始
本机搭建的环境为:Oracle(scott/tiger),Xp,Hibernate4.1.8,Junit
废话不多少,开始上代码:
一、首先来看多对一:
Student实体类:
package org.yanglg.hibernate.domain;
public class Student {
private String id;
private String name;
private String idcard;
private Classroom classroom;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getIdcard() {
return idcard;
}
public void setIdcard(String idcard) {
this.idcard = idcard;
}
public Classroom getClassroom() {
return classroom;
}
public void setClassroom(Classroom classroom) {
this.classroom = classroom;
}
}
Classroom实体类:
package org.yanglg.hibernate.domain;
import java.util.HashSet;
import java.util.Set;
public class Classroom {
private int id;
private String name;
private String classno;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getClassno() {
return classno;
}
public void setClassno(String classno) {
this.classno = classno;
}
}
Student.hbm.xml映射文件:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="org.yanglg.hibernate.domain">
<class name="Student" table="t_student">
<id name="id">
<generator class="uuid"></generator>
</id>
<property name="name" length="20" />
<property name="idcard" length="30" />
<many-to-one name="classroom" column="cid"></many-to-one>
</class>
</hibernate-mapping>
先看第一个添加Test
@Test
public void add1() {
Session session = null;
Transaction tran = null;
try {
session = HibernateUtil.openSession();
tran = session.beginTransaction();
Classroom c = new Classroom();
c.setName("09网本");
c.setClassno("200920120121");
session.save(c);
Student s1 = new Student();
s1.setIdcard("fsadfasdf");
s1.setName("name001");
s1.setClassroom(c);
Student s2 = new Student();
s1.setIdcard("fsadfasdf222");
s1.setName("name002");
s1.setClassroom(c);
Student s3 = new Student();
s1.setIdcard("fsadfasdf333");
s1.setName("name003");
s1.setClassroom(c);
session.save(s1);
session.save(s2);
session.save(s3);
tran.commit();
} catch (Exception e) {
} finally {
HibernateUtil.closeSession(session);
}
}
此时发出如下4条sql(SEQUENCE不算入其中):
Hibernate: select hibernate_sequence.nextval from dual
Hibernate: insert into t_classroom (name, classno, id) values (?, ?, ?)
Hibernate: insert into t_student (name, idcard, cid, id) values (?, ?, ?, ?)
Hibernate: insert into t_student (name, idcard, cid, id) values (?, ?, ?, ?)
Hibernate: insert into t_student (name, idcard, cid, id) values (?, ?, ?, ?)
这种方式,首先保存Classroom(一的一端),然后保存Student(用多的一端设置一的一端的属性,形如:s1.setClassroom(c);),也就是说,用多的一端来维护关系
咱们再看下一种方式:
@Test
public void add2() {
Session session = null;
Transaction tran = null;
try {
session = HibernateUtil.openSession();
tran = session.beginTransaction();
Student s1 = new Student();
s1.setIdcard("fsadfasdf");
s1.setName("name001");
session.save(s1);
Student s2 = new Student();
s1.setIdcard("dsaff");
s1.setName("namfasdfasde002");
session.save(s2);
Student s3 = new Student();
s1.setIdcard("fsdaf");
s1.setName("name0fasdfas03");
session.save(s3);
Classroom c = new Classroom();
c.setName("09ddsfsd");
c.setClassno("20092012we0122321");
session.save(c);
s1.setClassroom(c);
s2.setClassroom(c);
s3.setClassroom(c);
session.save(s1);
session.save(s2);
session.save(s3);
tran.commit();
} catch (Exception e) {
} finally {
HibernateUtil.closeSession(session);
}
}
这次采用了相反的方法,先save多的一端再save一的一端,用一的一端来维护关系,所以发出如下sql:
Hibernate: select hibernate_sequence.nextval from dual
Hibernate: insert into t_student (name, idcard, cid, id) values (?, ?, ?, ?)
Hibernate: insert into t_student (name, idcard, cid, id) values (?, ?, ?, ?)
Hibernate: insert into t_student (name, idcard, cid, id) values (?, ?, ?, ?)
Hibernate: insert into t_classroom (name, classno, id) values (?, ?, ?)
Hibernate: update t_student set name=?, idcard=?, cid=? where id=?
Hibernate: update t_student set name=?, idcard=?, cid=? where id=?
Hibernate: update t_student set name=?, idcard=?, cid=? where id=?
很明显,这样维护关系很复杂(多发了SQL)。
所以:多对一的时候,先保存少的一方,然后再保存多的一方,由多的一端维护关系。
咱们来做另一个实验:
@Test
public void testCasdade() {
Session session = null;
try {
session = HibernateUtil.openSession();
session.beginTransaction();
Classroom c = new Classroom();
c.setClassno("09计算机科学");
c.setName("DDDD");
//注意这里没有保存c哦!!
Student s1 = new Student();
s1.setName("ewrw");
s1.setIdcard("76756756");
s1.setClassroom(c);
session.save(s1);
session.getTransaction().commit();
} catch (Exception e) {
if (session != null) {
session.getTransaction().rollback();
}
e.printStackTrace();
} finally {
HibernateUtil.closeSession(session);
}
}
不好意思报错了
org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: org.yanglg.hibernate.domain.Classroom
为什么呢,很明显嘛,我们没有保存c,c还是瞬时状态,数据库里还没有,然后Student就要调用它,很明显会出错的!怎么办呢,我不会告诉你, cascade!!
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="org.yanglg.hibernate.domain">
<class name="Student" table="t_student">
<id name="id">
<generator class="uuid"></generator>
</id>
<property name="name" length="20" />
<property name="idcard" length="30" />
<many-to-one name="classroom" column="cid" cascade="all"></many-to-one>
</class>
</hibernate-mapping>
好了,cascade设置为all,就表示无论是增删改查,都能级联啦,所以再次运行testCasdade,你会发现一切正常了,也就是说保存的时候级联的保存。
BUT,问题也随之而来,设想一种情况,如果我们要删除一个学生的信息,那么由于级联存在,就会把这个学生所在的班级也删了!想来都不可思议 !所以看来呀,这个cascade还是少用的好,记好了哦!不过有一种情况还是可以用的,比如说我们要删除一个班级,加上cascade就会把班级里所有的学生都删了,这样貌似合情合理的,有和不可呢,但要记住,此时不能再是cascade="all"啦,应该是cascade=“delete”了吧。
总结一下:
多对一时:
1、尽量用多的一端来维护关系,save时先一后多,用多设置一,发出的SQL最少
2、cascade最好少用,记住一种情况,删除一的时候同时删除多,这时可用。