一对一关联有三种情况:
一是关联的实体都共享同样的主键,二是其中一个实体通过外键关联到另一个实体的主键 ,三是通过关联表来保存两个实体之间的连接关系。
接下来要介绍的是,注解形式的一对一单向外键关联的情况。
环境 : JDK 1.6,eclipse 3.6,maven 3.0.4,hibernate 3.3.2,junit 4.7,mysql 5.1
注 : 此处配置 pom.xml 是使用 maven 来管理 jar 包,如果你没有使用 maven,则需手动导入相关 jar 包。
①一对一单向外键关联 :
@OneToOne 建立实体 bean 之间的一对一的关联
cascade 级联策略,即,当对主对象做某种操作时,是否对其相关联的子对象也做相对应的操作。它有5个值可选,分别是 :
CascadeType.PERSIST : 级联新建
CascadeType.REMOVE : 级联删除
CascadeType.REFRESH : 级联刷新
CascadeType.MERGE : 级联更新
CascadeType.ALL : 囊括以上四项
fetch 抓取策略,它有2个值可选,分别是 :
FetchType.LAZY : 延迟抓取
FetchType.EAGER : 立即抓取
Tips : 延迟抓取数据能够保证应用只有在需要的时候才去数据库抓取相应的数据记录,这样能够避免过多,
或过早的加载数据库表中的数据,从而减少应用内存的开销。
@JoinColumn 该注解与@Column 注解用法有点相似,可以通过name来指定联接列的名称,如果没有该注解没有被声明,
默认的联接列名称是 : 关联的类的短类名(首字母小写,不带包名)_id。
}
@Test
public void update(){
session.beginTransaction();
Student student = (Student)session.get(Student.class, ID);
student.setName("fancydeepin");
// StudentCard studentCard = student.getStudentCard();
// studentCard.setDate(new Date());
// student.setStudentCard(studentCard);
session.update(student);
session.getTransaction().commit();
}
@Test
public void delete(){
session.beginTransaction();
Student student = (Student)session.get(Student.class, ID);
// StudentCard studentCard = student.getStudentCard();
// session.delete(studentCard);
session.delete(student);
session.getTransaction().commit();
}
}1. 建表
在 Junit 测试类中执行建表方法 createTable,数据库中生成表结构 :
2. 插入数据 ( 级联插入 )
在 Junit 测试类中执行 insert 方法,后台发出两条插入的 SQL 语句,数据库中产生的数据 :
在这里,student 是主表,studentcard 是从表,Student 类级联 (
CascadeType.ALL ) 了 StudentCard 类,当 Student 的实例对象被持久化时,
若 Student 对象的 StudentCard 实例对象不为 null,则该 StudentCard 对象也将被持久化到数据库,若为 null,则不会被持久化。
3. 查询数据 ( 延迟加载 )
在 Junit 测试类中执行 query 方法,后台发出 Student 的 select SQL 语句 :
Hibernate:
select
student0_.id as id0_0_,
student0_.name as name0_0_,
student0_.studentCard_id as studentC3_0_0_
from
Student student0_
where
student0_.id=?
若将 query 方法里被注释的行去掉,后台除了会发出 Student 的 select SQL 语句之外,还会发出 StudentCard 的 select SQL :
Hibernate:
select
student0_.id as id0_0_,
student0_.name as name0_0_,
student0_.studentCard_id as studentC3_0_0_
from
Student student0_
where
student0_.id=?
Hibernate:
select
studentcar0_.id as id1_0_,
studentcar0_.date as date1_0_
from
StudentCard studentcar0_
where
studentcar0_.id=?
4. 更新数据 ( 级联更新 )
在 Junit 测试类中执行 update 方法,后台发出 Student 的 update SQL 语句 : Hibernate:
update
Student
set
name=?,
studentCard_id=?
where
id=?
若将 update 方法中的注释行去掉,
后台除了会发出 Student 的 update SQL 语句之外,还会发出 StudentCard 的 update SQL :
Hibernate:
update
Student
set
name=?,
studentCard_id=?
where
id=?
Hibernate:
update
StudentCard
set
date=?
where
id=?
注 : 只有当 Student 对象的属性值发生变化时,才会发出 Student 的 update SQL,如果 Student 对象中的属性值没有发生过改变,
则不会发出 Student 的 update SQL ; StudentCard 也是一样的。5. 删除数据 ( 级联删除 )
在 Junit 测试类中执行 delete 方法,后台发出 Student 和 StudentCard 的 delete SQL 语句 :
Hibernate:
delete
from
Student
where
id=?
Hibernate:
delete
from
StudentCard
where
id=? 由于是
CascadeType.ALL 的级联策略,当从表中的记录被删除时,主表中被关联的记录也将会被删除掉。
若是将 delete 方法中的注释行去掉,将最后注释行的下一行注释掉,也就是如果将
session.delete(student); 这行 注释起来的话,
后台将抛出
org.hibernate.ObjectDeletedException 的异常,这是由于从表 student 关联了主表 studentcard,因此不能直接去删除
studentcard 表中被 student 表参考的记录,换句话说就是,在记录关联情况下,只有从表中的记录先被删除,主表中的记录才有可能被删除。
②一对一双向外键关联 : 如果,StudentCard 中的 Student 是必须的,也就是说,在 Student 中保存了一个 StudentCard 的引用,在 StudentCard 中也保存了一个 Student 的引用,
这就成了一对一的双向关联,StudentCard 的代码修改成 :
mappedBy :
相当于 xml 方式配置的 inverse = "true",表示将表间关联的这种关系的维护交给对方,对方才是关系的真正维护者,拥有主导权。
在双向关联中,有且仅有一端是作为主体( owner )端存在,主体端负责维护联接列。对于不需要维护这种关系的从表则通过 mappedBy 属性进行声明。
最后不必也不能再在被关联端(owned side)定义联接列了,因为已经在主体端进行了声明.
posted on 2012-10-13 13:20
fancydeepin 阅读(7808)
评论(0) 编辑 收藏