Hibernate关联关系之一对一

Hibernate关联关系之一对一
1.一对一关联
1.1.单向一对一外键关联
实体类中属性,因为是单向一对一,从Person到IdCard,所以Person中多一个能存放IdCard实例对象的属性。
在这里插入图片描述
IdCard.java和IdCard.hbm.xml

public class IdCard {
    private int id;
private String cardNo;
//省略setter/getter方法
}

IdCard.hbm.xml:
<hibernate-mapping package="com.zking.pojo">
    <class name="IdCard" table="idcard">
        <id name="id" column="id">
            <!-- 主键生成策略 -->
            <generator class="native" />    
        </id>
        <!-- 一些常规属性 -->
        <property name="cardNo"></property>
    </class>
</hibernate-mapping>

Person.java和Person.hbm.xml

public class Person {
    private int id;
    private String name;
private IdCard idCard;
// 省略setter/getter方法
}

Person.hbm.xml:
<hibernate-mapping package="com.zking.pojo">
    <class name="Person" table="person">
        <id name="id" column="id">
            <!-- 主键生成策略 -->
            <generator class="native" />    
        </id>
        <!-- 一些常规属性 -->
        <property name="name"></property>
     <!-- name表示外键对象名
               column表示外键字段名
               unique表示是否唯一
跟多对一一样,只是增加了一个unique属性。这样就指定了这端为一了。-->
        <many-to-one name="idCard" column="cardId" unique="true"></many-to-one>
</class>
</hibernate-mapping>  

测试数据为,看到这个图就应该知道我们这里是用外键关系了,在person表中有一个外键字段值。
在这里插入图片描述

真正的测试一下单向一对一,其实也就是从person能查到idcard,但是从idcard查不到person。

//这样会报异常,因为我们设置的是单向一对一,从person到Idcard,所以从idcard是查不到person。java.lang.NullPointerException
IdCard idCard = (IdCard)session.get(IdCard.class, 1);
System.out.println(idCard.getPerson().getName());;

//但是这样就查得到一个人的idCard
Person person = (Person)session.get(Person.class1);
person.getIdCard().getCardNo();

1.2.双向一对一外键关联
双向也很简单,只要改变两个地方,就在IdCard.java和IdCard.hbm.xml中加入这种映射关系就足够了,数据库关系图还是跟单向一对一外键关系一样。

在这里插入图片描述

IdCard.java和IdCard.hbm.xml

public class IdCard {
    private int id;
    private String cardNo;
private Person person;    //用来存放person对象,一对一关系
//省略setter/getter方法
}

IdCard.hbm.xml:
<hibernate-mapping package="com.zking.pojo">
    <class name="IdCard" table="idcard">
        <id name="id" column="id">
            <!-- 主键生成策略 -->
            <generator class="native" />   
        </id>
        <!-- 一些常规属性 -->
        <property name="cardNo"></property>
        <!-- 要注意property-ref这个属性,很重要,关键的地方就在这里。
        property-ref:指定关联类的属性名,这个属性将会和本类的主键相对应。
如果没有指定,
        会使用对方关联类的主键来跟本类的主键比较,这里要注意不是关联表中的外键字段名。如果不指定这个属性,那么一对一默认会使用主键去做对比。相当于原本我们是可以通过本类的主键去和关联类的外键比较,然后来找到对应记录的,但是这里一对一中没有column属性,所以该方法行不通,因此就想出了这种办法,不跟外键比,也不能跟主键比(因为不是主键关系),那么就跟关联表中的一个属性比,也就是我们这个person中的idCard属性,为什么找得到呢,因为从person能找到idcard,那么person中的idCard中就会有对应的值,我们跟该值比,也就能找到对应的person了。
        class:person所在的类,这个也可以不写,hibernate会自动帮我们找到
         -->
        <one-to-one name="person" class="Person" property-ref="idCard"></one-to-one>
    </class>
</hibernate-mapping>

Person类和Person.hbm.xml:

public class Person {
    private int id;
    private String name;
private IdCard idCard;
// 省略setter/getter方法
}

Person.hbm.xml:
<hibernate-mapping package="com.zking.pojo">
    <class name="Person" table="person">
        <id name="id" column="id">
            <!-- 主键生成策略 -->
            <generator class="native" />    
        </id>
        <!-- 一些常规属性 -->
        <property name="name"></property>
     <!-- name表示外键对象名
               column表示外键字段名
               unique表示是否唯一
跟多对一一样,只是增加了一个unique属性。这样就指定了这端为一了。-->
        <many-to-one name="idCard" column="cardId" unique="true"></many-to-one>
</class>
</hibernate-mapping>  

测试:这样从IdCard就能找到person了。而不是报空指针异常

一对一关联总结:
1、单向一对一主键关联、双向一对一主键关联、单向一对一外键关联、双向一对一外键关联的配置。
2、主键关联的特点:一个表中的主键就是外键,指向另一个表中的主键,所以两张表的主键是相同的,但是有一个缺点,就是必须依赖另一张表的主键,这在有些业务逻辑上是行不通的。
3、知道了单向一对一主键关联,那么双向一对一主键关联就非常的简单,其重点在主键id中的主键生成策略那块还有constrained属性的使用。
4、单向一对一外键关联其实就是多对一的一个特例,其中关键的地方在unique这个属性上面。
5、单向一对一外键关联知道后,双向一对一外键关联也非常简单,关键的地方就在中property-ref的配置,注意这个的意思是配置关联类中的属性,而不是关联类中的外键字段名。
6、one-to-one默认是使用主键和主键进行比较来查询数据,所以其中并没有column这个属性。因为没有这个column属性,所以就外键关联中就需要用到第5点的property-ref的属性了。

* get和load的区别

  • 1.发送SQL的时机:get方法是立即检索,当执行session.get()时马上发送SQL语句查询;load采用了一个技术.lazy延迟加载(懒加载),真正使用这个对象的数据时(对象的数据不包括主键)。
  • 2.返回的对象:get方法返回的是真实的对象;load方法返回的是代理对象。
  • 3.查询一个不存在的数据:get方法抛异常(NullPointException);load方法抛异常(ObjectNotFoundException)

问题:如果是双向一对一的,会不会出现死循环的现象?会,怎么处理?
解决办法:重写toString()只写一方,或者两边的toString()中都不写对方

猜你喜欢

转载自blog.csdn.net/qq_41730508/article/details/83824362