hibernate annotation 之 一对一单向外键关联

马士兵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();

}

}

  1. 建表

    在 Junit 测试类中执行建表方法 createTable,数据库中生成表结构 :

    hibernate annotation 之 一对一单向外键关联 - tuchengju - tuchengju的博客hibernate annotation 之 一对一单向外键关联 - tuchengju - tuchengju的博客

  2. 插入数据 ( 级联插入 )

    在 Junit 测试类中执行 insert 方法,后台发出两条插入的 SQL 语句,数据库中产生的数据 :

    hibernate annotation 之 一对一单向外键关联 - tuchengju - tuchengju的博客hibernate annotation 之 一对一单向外键关联 - tuchengju - tuchengju的博客

    在这里,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 表参考的记录。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值