马士兵Hibernate -annotation 学习笔记十分详细
http://www.hongyanliren.com/2014m11/18714.html
一对一关联有三种情况:
一是关联的实体都共享同样的主键,二是其中一个实体通过外键关联到另一个实体的主键 ,三是通过关联表来保存两个实体之间的连接关系。
接下来要介绍的是,注解形式的一对一单向外键关联的情况。
环境 : JDK 1.6,eclipse 3.6,maven 3.0.4,hibernate 3.3.2,junit 4.7,mysql 5.1
pom.xml 核心部分清单
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>3.3.2.GA</version>
</dependency>
<!-- Hibernate Dependency Start -->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2</version>
</dependency>
<dependency>
<groupId>javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.9.0.GA</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-annotations</artifactId>
<version>3.4.0.GA</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.5.8</version>
</dependency>
<!-- Hibernate Dependency End -->
<!-- mysql driver -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.17</version>
</dependency>
<!-- junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.7</version>
<scope>test</scope>
</dependency>
注 : 此处配置 pom.xml 是使用 maven 来管理 jar 包,如果你没有使用 maven,则需手动导入相关 jar 包。
实体 bean
package net.yeah.fancydeepin.unidirectional.po;
import java.io.Serializable;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import org.hibernate.annotations.GenericGenerator;
@Entity
public class Student implements Serializable{
private static final long serialVersionUID = 1L;
private String id;
private String name;
private StudentCard studentCard;
@Id
@GenericGenerator(name = “idGenerator”, strategy = “uuid”)
@GeneratedValue(generator = “idGenerator”)
@Column(length = 32)
public String getId() {
return id;
}
@Column(length = 18, nullable = false)
public String getName() {
return name;
}
@OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
public StudentCard getStudentCard() {
return studentCard;
}
public void setId(String id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public void setStudentCard(StudentCard studentCard) {
this.studentCard = studentCard;
}
}
@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。
实体 bean
package net.yeah.fancydeepin.unidirectional.po;
import java.io.Serializable;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
@Entity
public class StudentCard implements Serializable{
private static final long serialVersionUID = 1L;
private Long id;
private Date date;
@Id
public Long getId() {
return id;
}
@Column(nullable = false)
@Temporal(TemporalType.DATE)
public Date getDate() {
return date;
}
public void setId(Long id) {
this.id = id;
}
public void setDate(Date date) {
this.date = date;
}
}
hibernate.cfg.xml 清单
<session-factory>
<!-- Database connection settings -->
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="connection.url">jdbc:mysql://localhost:3306/temp</property>
<property name="connection.username">username</property>
<property name="connection.password">password</property>
<!-- SQL dialect -->
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- Enable Hibernate's automatic session context management -->
<property name="current_session_context_class">thread</property>
<!-- Echo all executed SQL to stdout -->
<property name="show_sql">true</property>
<property name="format_sql">true</property>
<!-- OneToOne 单向 -->
<mapping class="net.yeah.fancydeepin.unidirectional.po.Student" />
<mapping class="net.yeah.fancydeepin.unidirectional.po.StudentCard" />
<!-- OneToOne 双向 -->
<!--
<mapping class="net.yeah.fancydeepin.bidirectional.po.Student" />
<mapping class="net.yeah.fancydeepin.bidirectional.po.StudentCard" />
-->
</session-factory>
Junit Test
package junit.test;
import java.util.Date;
import net.yeah.fancydeepin.unidirectional.po.Student;
import net.yeah.fancydeepin.unidirectional.po.StudentCard;
import org.hibernate.Session;
import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.tool.hbm2ddl.SchemaExport;
import org.junit.BeforeClass;
import org.junit.Test;
public class TestApp {
private static Session session;
private static final String ID = “402881f13a5480c2013a5480c3d00001”;
@BeforeClass
public static void beforeClass(){
session = new AnnotationConfiguration().configure().buildSessionFactory().getCurrentSession();
}
@Test
public void createTable(){
new SchemaExport(new AnnotationConfiguration().configure()).create(true, true);
}
@Test
public void insert(){
Student student = new Student();
student.setName("fancy");
StudentCard studentCard = new StudentCard();
studentCard.setId(3110005981L);
studentCard.setDate(new Date());
student.setStudentCard(studentCard);
session.beginTransaction();
session.save(student);
session.getTransaction().commit();
}
@Test
public void query(){
session.beginTransaction();
Student student = (Student)session.get(Student.class, ID);
System.out.println(student.getName());
//StudentCard studentCard = student.getStudentCard();
//System.out.println(studentCard.getDate());
}
@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();
}
}
建表
在 Junit 测试类中执行建表方法 createTable,数据库中生成表结构 :
hibernate annotation 之 一对一单向外键关联 - tuchengju - tuchengju的博客hibernate annotation 之 一对一单向外键关联 - tuchengju - tuchengju的博客
插入数据 ( 级联插入 )
在 Junit 测试类中执行 insert 方法,后台发出两条插入的 SQL 语句,数据库中产生的数据 :
hibernate annotation 之 一对一单向外键关联 - tuchengju - tuchengju的博客hibernate annotation 之 一对一单向外键关联 - tuchengju - tuchengju的博客
在这里,student 是主表,studentcard 是从表,Student 类级联 ( CascadeType.ALL ) 了 StudentCard 类,当 Student 的实例对象被持久化时,
若 Student 对象的 StudentCard 实例对象不为 null,则该 StudentCard 对象也将被持久化到数据库,若为 null,则不会被持久化。
查询数据 ( 延迟加载 )
在 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=?更新数据 ( 级联更新 )
在 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 也是一样的。
删除数据 ( 级联删除 )
在 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 表参考的记录。