Hibernate单向多对一映射下的增删改查
注:作为初学者,本文仅为了巩固自己学习的知识亦或帮助初学者,如有缺漏,请见谅
在软件开发中,类与类之间最普遍的关系就是关联关系,而且关联关系是有方向的。以Student类和Grade类为例,一个年级包含多个学生,一个学生只对应一个年级,从Student到Grade就是多对一映射,从Grade到Student到Student就是一对多映射,同时包含两种关联关系就是双向多对一关系。本文仅介绍单向多对一映射关系。
一、配置单向多对一映射关系
以Student和Grade的关联关系为例,那么该如何来配置呢?既然一个Student只属于一个Grade,所以在Student持久类中应该定义一个Grade的对象;然后在映射文件中配置,下面详细介绍
1.
首先在Student类中定义一个Grade类的对象
public class Student implements Serializable{
private int id;
private int age;
private String name;
private Grade grade;
//...
}
2.
配置映射文件
<hibernate-mapping package="com.wzj.entity">
<class name="Student" table="Student">
<id name="id" type="java.lang.Integer" column="id">
<generator class="assigned"></generator>
</id>
<property name="name" type="java.lang.String" column="name"></property>
<property name="age" type="java.lang.Integer" column="age"></property>
<!-- 此句是关键 -->
<many-to-one name="grade" class="Grade" column="gradeid"></many-to-one>
</class>
<!--省去Grade映射-->
</hibernate-mapping>
二、单向多对一关系的使用
1.
增
我们首先创建两个Student对象,1个Grade对象,并建立关系,那么我们该以什么样的顺序来保存呢?
public static void main(String[] args) {
Session session=HibernateUtil.currentSession();
Transaction tx=session.beginTransaction();
testCreate(session);
tx.commit();
HibernateUtil.closeSession();
}
public static void testCreate(Session session){
Student s1=new Student(1,20,"student-1");
Student s2=new Student(2,20,"student-2");
Grade g=new Grade(1,"一年级");
s1.setGrade(g);
s2.setGrade(g);
//先保存“1”的一方,再保存“n”的一方
session.save(g);
session.save(s1);
session.save(s2);
}
然后运行,数据库中成功更新,控制台输出了3条insert语句,一条插入Grade,2条插入Student。再来看,先保存n的一方:
public static void testCreate(Session session){
Student s1=new Student(3,20,"student-3");
Student s2=new Student(4,20,"student-4");
Grade g=new Grade(2,"二年级");
s1.setGrade(g);
s2.setGrade(g);
//先保存“n”的一方,再保存“1”的一方
session.save(s1);
session.save(s2);
session.save(g);
}
然后运行,数据库成功更新,不过这次控制台输出了6条sql语句,第一条是查询年级是否存在,第2、3、4条是插入学生和年级,最后两条是更新学生的GradeId
小结:当我们先插入Student的时候,还要对应插入Grade的ID,此时数据库中并不存在这个Id,所以,Hibernate会先为我们插入一个空值(当然,数据库中的GradeId得允许为空),然后插入Grade之后再根据此时生成的GradeId去更新学生的信息;由此可见,这种方式增加了对数据库的访问频率,降低了程序的性能,所以推荐大家尽量少使用这种方式。
2.查
如下代码:
public static void testQuery(Session session){
Student s=(Student)session.get(Student.class, 1);
System.out.println(s.getName());
}
运行发现只是发送了一条sql语句,与之关联的Grade对象并没有查询;假如再加上一句:
Grade g=s.getGrade();
System.out.println(g.getGradeName());
此时再次运行就会发现变成了两条sql语句。倘若我们这样:
public static void testQuery(Session session){
Student s=(Student)session.get(Student.class, 1);
System.out.println(s.getName());
session.close();
Grade g=s.getGrade();
System.out.println(g.getGradeId());
System.out.println(g.getGradeName());
}
然后会发现,程序在执行g.getGradeName()的时候抛出了一个叫做LazyInitializationException的异常(为什么可以获取到Grade.GradeId呢?)其实这个异常就是Hibernate中常见的懒加载机制异常。
小结:当我们查询“n”的一方时,默认情况下只会查询到n的一方的对象,而与之关联的对象并不会查询,这就是Hibernate中的懒加载(延迟加载)机制。当我们需要使用到关联对象的属性的时候,Hibernate才会发送对应的sql语句去查询并实例化Grade,在实例化之前Grade只是一个代理对象,仅仅拥有一个和Student关联的属性值(GradeId),而其他属性统统无值,关于懒加载的详解,这里有一篇不错的 文章,大家可以参考一下:http://blog.csdn.net/sanjy523892105/article/details/7071139
3.改、删
对于这两种情况来说,使用起来就比较简单了,没有什么特别之处。
需要注意的是:执行删除时,在不设定级联的情况下,并且“1”的一方有“n”的一方在引用的时候,不能直接删除“1”这一方的对象。