hibernate annotation 注解一对一单向外键关联



hibernate一对一关联有三种情况:一是关联的实体都共享同样的主键,二是其中一个实体通过外键关联到另一个实体的主键 ,三是通过关联表来保存两个实体之间的连接关系。

接下来要介绍的是,注解形式的一对一单向外键关联的情况。

环境 : JDK 1.6,eclipse 3.6,maven 3.0.4,hibernate 3.3.2,junit 4.7,mysql 5.1

pom.xml 核心部分清单

<dependencies>

 

<!– Hibernate framework –>

<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>

 

</dependencies>

 

注 : 此处配置 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 清单

 

<hibernate-configuration>

<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>

</hibernate-configuration>

 

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();

}

}

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 表参考的记录。

http://www.2cto.com/kf/201210/160900.html