深入解析Java的Hibernate框架中的一对一关联映射

 更新时间:2016年01月03日 15:55:51   作者:cxshun  
这篇文章主要介绍了Java的Hibernate框架的一对一关联映射,包括对一对一外联映射的讲解,需要的朋友可以参考下

作为一个ORM框架,hibernate肯定也需要满足我们实现表与表之间进行关联的需要。hibernate在关联方法的实现很简单。下面我们先来看看一对一的做法:
 不多说了,我们直接上代码:
 两个实体类,TUser和TPassport:

public class TUser implements Serializable{ 
 
 private static final long serialVersionUID = 1L; 
 private int id; 
 private int age; 
 private String name; 
 private TPassport passport; 
  //省略Get/Set方法 
} 
public class TPassport implements Serializable{ 
 
 private static final long serialVersionUID = 1L; 
 private int id; 
 private String serial; 
 private int expiry; 
 private TUser user; 
  //省略Get/Set方法 
} 

  下面我们看一下映射文件有什么不同:

<hibernate-mapping package="org.hibernate.tutorial.domain4"> 
 <class name="TUser" table="USER4"> 
  <id name="id" column="id"> 
   <generator class="native" /> 
  </id> 
  <property name="name" type="java.lang.String" column="name"/> 
  <property name="age" type="java.lang.Integer" column="age"/> 
  <one-to-one name="passport" class="TPassport" 
     cascade="all" outer-join="true" /> 
 </class> 
</hibernate-mapping> 

  这里我们看到有一个新标签,one-to-one,它表明当前类与所对应的类是一对一的关系,cascade是级联关系,all表明无论什么情况都进行级联,即当对TUser类进行操作时,TPassport也会进行相应的操作,outer-join是指是否使用outer join语句。
 我们再看另外一个TPassport的映射文件:

<hibernate-mapping package="org.hibernate.tutorial.domain4"> 
 <class name="TPassport" table="passport4"> 
  <id name="id" column="id"> 
   <generator class="foreign" > 
    <param name="property">user</param> 
   </generator> 
  </id> 
  <property name="serial" type="java.lang.String" column="serial"/> 
  <property name="expiry" type="java.lang.Integer" column="expiry"/> 
  <one-to-one name="user" class="TUser" constrained="true" /> 
 </class> 
</hibernate-mapping>

  
  这里我们重点看到generator的class值,它为foreign表明参照外键,而参照哪一个是由param来进行指定,这里表明参照User类的id。而one-to-one标签中多了一个constrained属性,它是告诉hibernate当前类存在外键约束,即当前类的ID根据TUser的ID进行生成。
 下面我们直接上测试类,这次测试类没有用JUnit而是直接Main方法来了:

public static void main(String[] args) { 
   
  Configuration cfg = new Configuration().configure(); 
  SessionFactory sessionFactory = cfg.buildSessionFactory(); 
  Session session = sessionFactory.openSession(); 
   
  session.beginTransaction(); 
   
  TUser user = new TUser(); 
  user.setAge(20); 
  user.setName("shunTest"); 
   
  TPassport passport = new TPassport(); 
  passport.setExpiry(20); 
  passport.setSerial("123123123"); 
   
  passport.setUser(user); 
  user.setPassport(passport); 
   
  session.save(user); 
   
  session.getTransaction().commit(); 
   
 } 

  代码很简单,就不说了。我们主要看这里:

session.save(user); 

  这里为什么我们只调用一个save呢,原因就在我们的TUser映射文件中的cascade属性,它被设为all,即表明当我们对TUser进行保存,更新,删除等操作时,TPassport也会进行相应的操作,所以这里我们不用写session.save(passport)。我们看到后台:

Hibernate: insert into USER4 (name, age) values (?, ?) 
Hibernate: insert into passport4 (serial, expiry, id) values (?, ?, ?) 
Hibernate:   它打印出两个语句,证明hibernate确定帮我们做了这个工作。
 
 
 下面我们再来一个测试类,测试查询:
public static void main(String[] args) { 
  Configuration cfg = new Configuration().configure(); 
  SessionFactory sessionFactory = cfg.buildSessionFactory(); 
  Session session = sessionFactory.openSession(); 
   
  TUser user = (TUser)session.load(TUser.class,new Integer(3)); 
  System.out.println(user.getName()+":"+user.getPassport().getSerial()); 
   
 } 
  这里我们通过查询出TUser类,取到TPassport对象。
 我们可以看到hibernate的SQL语句是:
复制代码 代码如下:

Hibernate:
select tuser0_.id as id0_1_, tuser0_.name as name0_1_, tuser0_.age as age0_1_, tpassport1_.id as id1_0_, tpassport1_.serial as serial1_0_, tpassport1_.expiry as expiry1_0_ from USER4 tuser0_ left outer join passport4 tpassport1_ on tuser0_.id=tpassport1_.id where tuser0_.id=?

  我们看到语句当中有left outer join,这是因为我们前面在one-to-one当中设了outer-join="true",我们试着把它改成false,看到SQL语句如下:
复制代码 代码如下:

Hibernate:
select tuser0_.id as id0_0_, tuser0_.name as name0_0_, tuser0_.age as age0_0_ from USER4 tuser0_ where tuser0_.id=?
Hibernate:
select tpassport0_.id as id1_0_, tpassport0_.serial as serial1_0_, tpassport0_.expiry as expiry1_0_ from passport4 tpassport0_ where tpassport0_.id=?


  现在是分成两条来查了,根据第一条查出的ID再到第二条查出来。
 
 也许很多人会问为什么测试的时候不用TPassport查出TUser呢,其实也可以的,因为它们是一对一的关系,谁查谁都是一样的。

外键关联
现在我们看一下通过外键来进行关联的一对一关联。
 还是一贯的直接上例子:我们写了两个实体类,TGroup和TUser

public class TGroup implements Serializable{ 
 
 private static final long serialVersionUID = 1L; 
 private int id; 
 private String name; 
 private TUser user; 
  //省略Get/Set方法 
} 
public class TUser implements Serializable{ 
 
 private static final long serialVersionUID = 1L; 
 private int id; 
 private int age; 
 private String name; 
 private TGroup group; 
  //省略Get/Set方法 
  
} 

  实体类完了我们就看一下映射文件:

<hibernate-mapping package="org.hibernate.tutorial.domain5"> 
 <class name="TUser" table="USER5"> 
  <id name="id" column="id"> 
   <generator class="native" /> 
  </id> 
  <property name="name" type="java.lang.String" column="name"/> 
  <property name="age" type="java.lang.Integer" column="age"/> 
  <many-to-one name="group" class="TGroup" column="group_id" unique="true" /> 
 </class> 
</hibernate-mapping> 

  这里我们看到是用many-to-one标签而不是one-to-one,为什么呢?
 这里以前用的时候也没多在注意,反正会用就行,但这次看了夏昕的书终于明白了,实际上这种通过外键进行关联方式只是多对一的一种特殊方式而已,我们通过unique="true"限定了它必须只能有一个,即实现了一对一的关联。
 接下来我们看一下TGroup的映射文件:

<hibernate-mapping package="org.hibernate.tutorial.domain5"> 
 <class name="TGroup" table="group5"> 
  <id name="id" column="id"> 
   <generator class="native" /> 
  </id> 
  <property name="name" type="java.lang.String" column="name"/> 
  <one-to-one name="user" class="TUser" property-ref="group" /> 
 </class> 
</hibernate-mapping> 

  这里,注意,我们又用到了one-to-one,表明当前的实体和TUser是一对一的关系,这里我们不用many-to-one,而是通过one-to-one指定了TUser实体中通过哪个属性来关联当前的类TGroup。这里我们指定了TUser是通过group属性和Tuser进行关联的。property-ref指定了通过哪个属性进行关联。
 下面我们看测试类:

public class HibernateTest { 
 
 public static void main(String[] args) { 
 
  Configuration cfg = new Configuration().configure(); 
  SessionFactory sessionFactory = cfg.buildSessionFactory(); 
  Session session = sessionFactory.openSession(); 
   
  session.beginTransaction(); 
   
  TGroup group = new TGroup(); 
  group.setName("testGroup"); 
   
  TUser user = new TUser(); 
  user.setAge(23); 
  user.setName("test"); 
   
  user.setGroup(group); 
  group.setUser(user); 
   
  session.save(group); 
  session.save(user); 
   
  session.getTransaction().commit(); 
  session.close(); 
 } 
 
} 

  注意,这次我们的代码中需要进行两次的保存,因为它们对各自都有相应的对应,只保存一个都不会对另外一个有什么操作。所以我们需要调用两次保存的操作。最后进行提交。
 hibernate打印出语句:

Hibernate: insert into group5 (name) values (?) 
Hibernate: insert into USER5 (name, age, group_id) values (?, ?, ?) 

  这说明我们正确地存入了两个对象值。
 
 我们写多一个测试类进行查询:

public static void main(String[] args) { 
 
  Configuration cfg = new Configuration().configure(); 
  SessionFactory sessionFactory = cfg.buildSessionFactory(); 
  Session session = sessionFactory.openSession(); 
   
  TUser user = (TUser)session.load(TUser.class,new Integer(1)); 
  System.out.println("From User get Group:"+user.getGroup().getName()); 
   
   
  TGroup group = (TGroup)session.load(TGroup.class,new Integer(1)); 
  System.out.println("From Group get User:" + group.getUser().getName()); 
   
  session.close(); 
   
 } 

  我们都可以得到正确的结果,这表明我们可以通过两个对象拿出对方的值,达到了我们的目的。
 这个例子中用到的TGroup和TUser只是例子而已,实际上现实生活中的user一般都对应多个group。

相关文章

  • Java web实现账号单一登录,防止同一账号重复登录(踢人效果)

    Java web实现账号单一登录,防止同一账号重复登录(踢人效果)

    这篇文章主要介绍了Java web实现账号单一登录,防止同一账号重复登录,有点类似于qq登录踢人效果,本文给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2019-10-10
  • SpringBoot深入讲解单元测试与热部署应用

    SpringBoot深入讲解单元测试与热部署应用

    这篇文章介绍了SpringBoot单元测试与热部署,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-06-06
  • SpringBoot实现文件下载功能的方式分享

    SpringBoot实现文件下载功能的方式分享

    这篇文章主要为大家详细介绍了SpringBoot这哪个实现文件下载功能的几种方式,文中的实现方法简介易懂,感兴趣的小伙伴可以跟随小编一起学习一下
    2023-03-03
  • Nacos入门过程的坑--获取不到配置的值问题

    Nacos入门过程的坑--获取不到配置的值问题

    这篇文章主要介绍了Nacos入门过程的坑--获取不到配置的值问题及解决,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-01-01
  • mybatis框架入门学习教程

    mybatis框架入门学习教程

    MyBatis是一个支持普通SQL查询,存储过程和高级映射的优秀持久层框架。这篇文章主要介绍了mybatis框架入门学习教程,需要的朋友可以参考下
    2017-02-02
  • 剑指Offer之Java算法习题精讲数组与字符串题

    剑指Offer之Java算法习题精讲数组与字符串题

    跟着思路走,之后从简单题入手,反复去看,做过之后可能会忘记,之后再做一次,记不住就反复做,反复寻求思路和规律,慢慢积累就会发现质的变化
    2022-03-03
  • Spring Cloud OpenFeign REST服务客户端原理及用法解析

    Spring Cloud OpenFeign REST服务客户端原理及用法解析

    这篇文章主要介绍了Spring Cloud OpenFeign REST服务客户端原理及用法解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-10-10
  • Java用Cookie限制点赞次数(简版)

    Java用Cookie限制点赞次数(简版)

    最近做了一个项目,其中有项目需求是,要用cookie实现限制点赞次数,特此整理,把实现代码分享给大家供大家学习
    2016-02-02
  • Java提示缺少返回语句的解决办法

    Java提示缺少返回语句的解决办法

    在本篇文章里小编给大家分享了关于Java提示缺少返回语句的解决办法以及相关知识点,需要的朋友们参考下。
    2019-07-07
  • Java RabbitMQ高级特性详细分析

    Java RabbitMQ高级特性详细分析

    为了保证消息的可靠性传输,包括投递消息的生产方能投递成功,和消息消费的消费方正确消费,RabbitMQ 提供了两个确认机制,由于消息按照流通的顺序从左到右,因此为保证可靠性,MQ必须对 Producer进行确认,Consumer 必须对 MQ 进行确认
    2022-08-08

最新评论