您的位置:首页 > 其它

Hibernate入门教程

2015-06-27 18:18 295 查看
Hibernate入门教程 第三章
Hibernate一对多、多对一、单边及双边配置

我们上篇文章主要讲了Hibernate的一对一的配置(2种情况),这篇文章主要说一下Hibernate的一对多和多对一的双边配置情况,如果我们只配置其中的一边关系,比如,我们只在一方配置关系那么以上情况就变为单边的一对多,如果我们只配置多方,那么就变成了单边多对一。所以以上我们说了3中情况,其实是差不多的,所以这里我们放到一起讲。很多人可能有的时候搞不清什么时候到底是单边还是双边,其实我们碰到具体的情况我们就知道了,比如学生和班级,这既是一对多、又是多对一,所以我们应该配置双边的。比如用户和邮箱,一个用户有多个邮箱,我们应该配置成单边的一对多的关系。再比如论文系统,多个文章对应一个类型,我们应该配置成单边的多对一关系。当然以上说的一对多和多对一你都可以配成双边的,主要看需求。这里大家只要搞清楚有这几种情况就好了。我们下面开始说重点。

预备知识;

inverse的设置,既然关系设计到单边和双边就涉及到关系到底由一方来维护,还是由多方来维护,Hibernate中默认是由多方来维护;比如学生和班级,学生的多方、班级是单方,那么默认由学生来维护他们之间的关系。

一、配置文件

1、学生类:

public class Student100  implements java.io.Serializable {

// Fields

private Integer sno;
private Class100 class100;
private String name;

// Constructors

/** default constructor */
public Student100() {
}

/** minimal constructor */
public Student100(Integer sno) {
this.sno = sno;
}

/** full constructor */
public Student100(Integer sno, Class100 class100, String name) {
this.sno = sno;
this.class100 = class100;
this.name = name;
}

// Property accessors

public Integer getSno() {
return this.sno;
}

public void setSno(Integer sno) {
this.sno = sno;
}

public Class100 getClass100() {
return this.class100;
}

public void setClass100(Class100 class100) {
this.class100 = class100;
}

public String getName() {
return this.name;
}

public void setName(String name) {
this.name = name;
}

@Override
public String toString() {
return "Student100 [class100=" + class100 + ", name=" + name + ", sno="
+ sno + "]";
}
}
2、学生配置文件

<?xml version="1.0" encoding="utf-8"?>
<!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.sunny.entity100.Student100" table="student100" catalog="test100">
<id name="sno" type="java.lang.Integer">
<column name="sno" />
<generator class="identity"></generator>
</id>
<property name="name" type="java.lang.String">
<column name="name" length="20" />
</property>
<many-to-one name="class100" class="com.sunny.entity100.Class100">
<column name="class_id" /><!-- Student100表中将会生成一个外键class_id 引用Class100中的id -->
</many-to-one>
</class>
</hibernate-mapping>


3、班级类

public class Class100  implements java.io.Serializable {

// Fields

private Integer id;
private String name;
private Set students = new HashSet();

// Constructors

/** default constructor */
public Class100() {
}

/** minimal constructor */
public Class100(Integer id) {
this.id = id;
}

/** full constructor */
public Class100(Integer id, String name, Set students) {
this.id = id;
this.name = name;
this.students = students;
}

// Property accessors

public Integer getId() {
return this.id;
}

public void setId(Integer id) {
this.id = id;
}

public String getName() {
return this.name;
}

public void setName(String name) {
this.name = name;
}

public Set getStudents() {
return students;
}

public void setStudents(Set students) {
this.students = students;
}
}
4、班级配置文件

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!--
Mapping file autogenerated by MyEclipse Persistence Tools
-->
<hibernate-mapping>
<class name="com.sunny.entity100.Class100" table="class100" catalog="test100">
<id name="id" type="java.lang.Integer">
<column name="id" />
<generator class="identity"></generator>
</id>
<property name="name" type="java.lang.String">
<column name="name" length="20" />
</property>
<set name="students"><!-- lazy默认为true既打开延时加载 -->
<key>
<column name="class_id" /><!-- 定义集合所对应的数据库表的外键,class_id位student表的外键 -->
</key>
<one-to-many class="com.sunny.entity100.Student100" />
</set>
</class>
</hibernate-mapping>
二、数据库操作

1、插入数据

public static void fun1(){
Session session = HibernateSessionFactory.getSession();
session.beginTransaction();
Student100 s1 = new Student100();
Class100 c = new Class100();
c.setName("三年二班");
s1.setName("apache");
s1.setClass100(c);//默认是多方维护关系,既关系由Student来维护
session.save(c);
session.save(s1);
session.getTransaction().commit();
session.close();
}


s1.setClass100(c);我们看到这里由Student来维护关系的,如果我们想让Class来维护关系应该这么做呢,如下:

在班级的配置文件中加上这一句

<set name="students" inverse="false"> 既不是由对方来控制关系那么就是自已来控制关系啦

那么我们fun1改写为如下:

public static void fun1_1(){
Session session = HibernateSessionFactory.getSession();
session.beginTransaction();
Student100 s1 = new Student100();
s1.setName("apache");
Class100 c = new Class100();
c.setName("三年二班");
c.getStudents().add(s1);//Class维护关系
session.save(s1);
session.save(c);
session.getTransaction().commit();
session.close();
}
补充:由于inverse一般设置在set上面,在一对一关系中,我们应该没有办法控制关系由谁来维护,一般是在有外键的哪一方维护的(个人认为)

2、查询

//查询
public static void fun2(){
Session session = HibernateSessionFactory.getSession();
session.beginTransaction();
Query query = session.createQuery("from Student100");
List<Student100> list = query.list();
for(Student100 stu:list){
System.out.println(stu.getClass100().getName());
}
}
产生n+1条sql语句,因为默认fetch为select

//fetch的使用
public static void fun4(){
Session session = HibernateSessionFactory.getSession();
session.beginTransaction();
Query query = session.createQuery("from Class100 c left join fetch c.students");
//Query query = session.createQuery("from Student100 s");
List<Class100> ss = query.list();
for(Class100 s : ss){
System.out.println(s);
}
}
由于lazy设置为true(默认),所以我们要用fetch把学生从班级里抓取出来,当然也可以不抓取,那么当要用到学生信息时候,Hibernate会自动抓取

3、删除与更新简单,没有设置级联的时候要考虑约束

三、对应相应的一对多和多对一的单边配置,只要删除对应的关系就可以了,这里不再啰嗦

说明:比如一对多的单边关系,则关系维护就有一方维护,比如本来中,我们删除Student中Class和相关的配置文件中的配置。现在的关系是一个班级对应多个学生这样的一对多的单边关系。那么这个时候关系就有一方既班级来维护,Hibernate中如果双边关系都在,则默认是由多方维护关系,如果是单边的,那么谁在谁维护关系,在此说明!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: